1class SignaturesController < ApplicationController |
|
2 include FormTracking |
|
4 before_action :retrieve_petition, only: [:new, :confirm, :create, :thank_you] |
|
5 before_action :retrieve_signature, only: [:verify, :unsubscribe, :signed] |
|
6 before_action :build_signature, only: [:new, :confirm, :create] |
|
7 before_action :expire_form_requests, only: [:new] |
|
8 before_action :expire_signed_tokens, only: [:verify] |
|
9 before_action :verify_token, only: [:verify] |
|
10 before_action :verify_signed_token, only: [:signed] |
|
11 before_action :verify_unsubscribe_token, only: [:unsubscribe] |
|
12 before_action :redirect_to_petition_page_if_rejected, only: [:new, :confirm, :create, :thank_you, :verify, :signed] |
|
13 before_action :redirect_to_petition_page_if_closed, only: [:new, :confirm, :create, :thank_you] |
|
14 before_action :redirect_to_petition_page_if_closed_for_signing, only: [:verify, :signed] |
|
15 before_action :do_not_cache |
|
17 rescue_from ActiveRecord::RecordNotUnique do |exception| |
|
18 @signature = @signature.find_duplicate! |
|
20 delete_form_request
|
|
21 send_email_to_petition_signer
|
|
23 redirect_to thank_you_url
|
|
24 end |
|
26 rescue_from ActiveRecord::RecordInvalid do |exception| |
|
27 respond_to do |format| |
|
28 format.html { render :new } |
|
29 end |
|
30 end |
|
|
32 def new |
33 respond_to do |format| |
|
34 format.html
|
|
35 end |
|
36 end |
|
|
38 def confirm |
39 respond_to do |format| |
|
40 format.html { render(@signature.valid? ? :confirm : :new) } |
|
41 end |
|
42 end |
|
|
44 def create |
45 if @signature.save! |
|
46 delete_form_request
|
|
47 send_email_to_petition_signer
|
|
49 redirect_to thank_you_url
|
|
50 end |
|
51 end |
|
|
53 def signed |
54 unless @signature.seen_signed_confirmation_page? |
|
55 @signature.mark_seen_signed_confirmation_page! |
|
56 end |
|
58 respond_to do |format| |
|
59 format.html
|
|
60 end |
|
61 end |
|
|
63 def verify |
64 unless @signature.validated? |
|
65 @signature.validate!(request: request) |
|
66 end |
|
68 store_signed_token_in_session
|
|
69 redirect_to signed_signature_url(@signature) |
|
70 end |
|
|
72 def unsubscribe |
73 @signature.unsubscribe!(token_param) |
|
75 respond_to do |format| |
|
76 format.html
|
|
77 end |
|
78 end |
|
|
80 def thank_you |
81 respond_to do |format| |
|
82 format.html
|
|
83 end |
|
84 end |
|
86 private
|
|
|
88 def petition_id |
89 @petition_id ||= Integer(params[:petition_id]) |
|
90 end |
|
|
92 def signature_id |
93 @signature_id ||= Integer(params[:id]) |
|
94 end |
|
|
96 def token_param |
97 @token_param ||= params[:token].to_s.encode('utf-8', invalid: :replace) |
|
98 end |
|
|
100 def expire_form_requests |
101 expired_form_requests.each do |id, token| |
|
102 cookies.delete(token)
|
|
103 form_requests.delete(id)
|
|
104 end |
|
105 end |
|
|
107 def expired_form_requests |
108 form_requests.each_with_object([]) do |(id, hash), expired| |
|
109 expired << [id, hash["form_token"]] if form_request_expired?(hash, form_request_max_age) |
|
110 end |
|
111 end |
|
|
113 def form_request_timestamps |
114 timestamps = form_requests.map { |_, r| r["form_requested_at"].in_time_zone } |
|
115 end |
|
|
117 def last_form_request_timestamp |
118 form_request_timestamps.sort[-10] |
|
119 end |
|
|
121 def form_request_max_age |
122 [last_form_request_timestamp, 1.day.ago].compact.max |
|
123 end |
|
|
125 def form_request_expired?(hash, max_age = 1.day.ago) |
126 hash["form_requested_at"].in_time_zone < max_age |
|
127 end |
|
|
129 def delete_form_request |
130 cookies.delete(form_token)
|
|
131 form_requests.delete(form_request_id)
|
|
132 end |
|
|
134 def signed_tokens |
135 @signed_tokens = session[:signed_tokens] || {} |
|
136 end |
|
|
138 def session_signed_token |
139 signed_tokens.delete(signature_id.to_s)
|
|
140 end |
|
|
142 def signed_token_hash |
143 { signature_id.to_s => @signature.signed_token } |
|
144 end |
|
|
146 def expire_signed_tokens |
147 signed_tokens.delete_if { |id, token| Signature.validated?(id) } |
|
148 end |
|
|
150 def store_signed_token_in_session |
151 session[:signed_tokens] = signed_tokens.merge(signed_token_hash) |
|
152 end |
|
|
154 def verify_token |
155 unless @signature.perishable_token == token_param |
|
156 raise ActiveRecord::RecordNotFound, "Unable to find Signature with token: #{token_param.inspect}" |
|
157 end |
|
158 end |
|
|
160 def verify_signed_token |
161 unless @signature.signed_token == session_signed_token |
|
162 redirect_to signed_token_failure_url
|
|
163 end |
|
164 end |
|
|
166 def verify_unsubscribe_token |
167 unless @signature.unsubscribe_token == token_param |
|
168 raise ActiveRecord::RecordNotFound, "Unable to find Signature with unsubscribe token: #{token_param.inspect}" |
|
169 end |
|
170 end |
|
|
172 def retrieve_petition |
173 @petition = Petition.visible.find(petition_id) |
|
174 end |
|
|
176 def retrieve_signature |
177 @signature = Signature.find(signature_id) |
|
178 @petition = @signature.petition |
|
180 unless @petition.visible? |
|
181 raise ActiveRecord::RecordNotFound, "Unable to find Signature with id: #{signature_id}" |
|
182 end |
|
183 end |
|
|
185 def build_signature |
186 if action_name == "new" |
|
187 @signature = @petition.signatures.build(signature_params_for_new) |
|
188 else |
|
189 @signature = @petition.signatures.build(signature_params_for_create) |
|
190 end |
|
191 end |
|
|
193 def thank_you_url |
194 thank_you_petition_signatures_url(@petition) |
|
195 end |
|
|
197 def signed_token_failure_url |
198 petition_url(@petition) |
|
199 end |
|
|
201 def redirect_to_petition_page_if_rejected |
202 if @petition.rejected? |
|
203 redirect_to petition_url(@petition), notice: "Sorry, you can't sign petitions that have been rejected" |
|
204 end |
|
205 end |
|
|
207 def redirect_to_petition_page_if_closed |
208 if @petition.closed? |
|
209 redirect_to petition_url(@petition), notice: "Sorry, you can't sign petitions that have been closed" |
|
210 end |
|
211 end |
|
|
213 def redirect_to_petition_page_if_closed_for_signing |
214 if @petition.closed_for_signing? |
|
215 redirect_to petition_url(@petition), notice: "Sorry, you can't sign petitions that have been closed" |
|
216 end |
|
217 end |
|
|
219 def send_email_to_petition_signer |
220 unless @signature.email_threshold_reached? |
|
221 if @signature.pending? |
|
222 EmailConfirmationForSignerEmailJob.perform_later(@signature) |
|
223 else |
|
224 EmailDuplicateSignaturesEmailJob.perform_later(@signature) |
|
225 end |
|
226 end |
|
227 end |
|
|
229 def signature_params_for_new |
230 {
|
|
231 location_code: "GB", |
|
232 form_token: form_token, |
|
233 form_requested_at: form_requested_at |
|
234 }
|
|
235 end |
|
|
237 def signature_params |
238 params.require(:signature).permit(*signature_attributes) |
|
239 end |
|
|
241 def signature_params_for_create |
242 signature_params.merge(
|
|
243 ip_address: request.remote_ip, |
|
244 form_token: form_token, |
|
245 form_requested_at: form_requested_at, |
|
246 image_loaded_at: image_loaded_at |
|
247 )
|
|
248 end |
|
|
250 def signature_attributes |
251 %i[name email email_confirmation postcode location_code uk_citizenship notify_by_email] |
|
252 end |
|
253end |