metadata_presenter 2.18.7 → 2.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/app/controllers/metadata_presenter/answers_controller.rb +7 -0
  4. data/app/controllers/metadata_presenter/engine_controller.rb +18 -0
  5. data/app/controllers/metadata_presenter/save_and_return_controller.rb +142 -22
  6. data/app/controllers/metadata_presenter/submissions_controller.rb +11 -0
  7. data/app/models/metadata_presenter/email_confirmation.rb +3 -7
  8. data/app/models/metadata_presenter/page.rb +2 -0
  9. data/app/models/metadata_presenter/resume_form.rb +16 -0
  10. data/app/models/metadata_presenter/saved_form.rb +19 -3
  11. data/app/validators/email_confirmation_validator.rb +3 -2
  12. data/app/validators/saved_progress_validator.rb +4 -0
  13. data/app/validators/secret_answer_validator.rb +7 -0
  14. data/app/views/metadata_presenter/page/checkanswers.html.erb +11 -3
  15. data/app/views/metadata_presenter/page/content.html.erb +9 -1
  16. data/app/views/metadata_presenter/page/multiplequestions.html.erb +9 -2
  17. data/app/views/metadata_presenter/page/singlequestion.html.erb +11 -1
  18. data/app/views/metadata_presenter/save_and_return/email_confirmation.html.erb +19 -16
  19. data/app/views/metadata_presenter/save_and_return/record_error.html.erb +9 -0
  20. data/app/views/metadata_presenter/save_and_return/record_failure.html.erb +9 -0
  21. data/app/views/metadata_presenter/save_and_return/record_link_expired.html.erb +9 -0
  22. data/app/views/metadata_presenter/save_and_return/record_link_used.html.erb +9 -0
  23. data/app/views/metadata_presenter/save_and_return/resume_from_start.html.erb +11 -0
  24. data/app/views/metadata_presenter/save_and_return/resume_progress.html.erb +50 -0
  25. data/app/views/metadata_presenter/save_and_return/return.html.erb +26 -0
  26. data/app/views/metadata_presenter/save_and_return/save_progress.html.erb +3 -3
  27. data/app/views/metadata_presenter/save_and_return/show.html.erb +37 -34
  28. data/config/locales/en.yml +36 -1
  29. data/config/routes.rb +8 -1
  30. data/lib/metadata_presenter/version.rb +1 -1
  31. metadata +25 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cda2ddb44cfc7b96722cff6acfe71ee950444f79887e2992c90a8e5378cee18
4
- data.tar.gz: cb6255fa36cd1885a52a17895e4f09eb96ff1776a574a75aba4e5db374133529
3
+ metadata.gz: b55fc1ebe10f65b4d0ebbaa969f4a1a77ca51ffa6a537329879294e10bc9058e
4
+ data.tar.gz: 7062a65a1e84854b1cade841121862576d417acf02347b263cd85f6817ebd180
5
5
  SHA512:
6
- metadata.gz: 57f991e50056dbb14a621fb8bb43676a68c4af6fe1d6f309f202bc69530dd85f847200e692214c93b152507eb0234995a76703c7ec5d25bcd4aeb6e22186aff8
7
- data.tar.gz: c23c04f42abe30539adb502113e13d7fc971b952ca905196e45542debec80e84471457cb62bc749a0159e461291fb2477f9f4bab65f5e81d936f5294676bc34d
6
+ metadata.gz: 5d0fe37a83a9f221ebc6055ae7034388746b13c715ca3d9c533d9128839847f51eafd01db6d9430a09232b00efd2b36a321ed6dbb78f3ea3edc71027ac9bc782
7
+ data.tar.gz: ce129d017803fddd5b02ebcc076909aeedff699f1c9443cf061501d1f9f64cdd74fe234b69c7a9b851af9649522abd8395686c0738055191d6724b6b7fb1b976
data/README.md CHANGED
@@ -95,6 +95,8 @@ The `autocomplete_items` takes the components on a page and retrieves any items
95
95
 
96
96
  `payment_link_url` method will present the payment link url. For the Runner this is the value of the `ENV['PAYMENT_LINK']` variable. In the Editor the value comes from the `ServiceConfiguration` table.
97
97
 
98
+ `save_and_return_enabled?` method checks whether save and return is enabled in the Runner or Editor app. In the Runner save and return is enabled when the `ENV['SAVE_AND_RETURN']` environment variable is present. In the Editor, save and return enabled can be ascertained by checking the `ServiceConfiguration` table.
99
+
98
100
  ## Generate documentation
99
101
 
100
102
  Run `rake doc` and open the doc/index.html
@@ -6,6 +6,12 @@ module MetadataPresenter
6
6
  @previous_answers = reload_user_data.deep_dup
7
7
  @page_answers = PageAnswers.new(page, answers_params, autocomplete_items(page.components))
8
8
 
9
+ if params[:save_for_later].present?
10
+ save_user_data
11
+ # NOTE: if the user is on a file upload page, files will not be uploaded before redirection
12
+ redirect_to save_path(page_slug: params[:page_slug]) and return
13
+ end
14
+
9
15
  upload_files if upload?
10
16
 
11
17
  if @page_answers.validate_answers
@@ -49,6 +55,7 @@ module MetadataPresenter
49
55
  end
50
56
 
51
57
  def answers_params
58
+ params.permit(:page_slug, :save_for_later)
52
59
  params[:answers] ? params[:answers].permit! : {}
53
60
  end
54
61
 
@@ -21,6 +21,24 @@ module MetadataPresenter
21
21
  end
22
22
  end
23
23
 
24
+ def get_saved_progress(uuid)
25
+ if defined? super
26
+ super(uuid)
27
+ end
28
+ end
29
+
30
+ def increment_record_counter(uuid)
31
+ if defined? super
32
+ super(uuid)
33
+ end
34
+ end
35
+
36
+ def invalidate_record(uuid)
37
+ if defined? super
38
+ super(uuid)
39
+ end
40
+ end
41
+
24
42
  def back_link
25
43
  previous_page = PreviousPage.new(
26
44
  service:,
@@ -1,31 +1,42 @@
1
1
  module MetadataPresenter
2
2
  class SaveAndReturnController < EngineController
3
- helper_method :secret_questions, :page_slug, :confirmed_email
3
+ helper_method :secret_questions, :page_slug, :confirmed_email, :get_service_name, :get_uuid, :label_text
4
4
 
5
5
  def show
6
6
  @saved_form = SavedForm.new
7
7
  end
8
8
 
9
9
  def page_slug
10
+ if session['returning_slug'].present?
11
+ return session['returning_slug']
12
+ end
10
13
  if session['saved_form'].present?
11
- session['saved_form']['page_slug']
14
+ return session['saved_form']['page_slug']
15
+ end
16
+ if params['saved_form'].present?
17
+ return params['saved_form']['page_slug']
12
18
  end
19
+
13
20
  params[:page_slug]
14
21
  end
15
22
 
16
23
  def confirmed_email
17
- session['saved_form']['email']
18
- # TODO: clear session data after submission is successful
24
+ email = session['saved_form']['email']
25
+ session[:saved_form] = nil
26
+
27
+ email
19
28
  end
20
29
 
21
30
  def create
22
31
  @saved_form = SavedForm.new
23
32
  @saved_form.populate_param_values(saved_form_params)
24
- @saved_form.secret_question = text_for(params['saved_form']['secret_question'])
33
+ @saved_form.secret_question_text = text_for(params['saved_form']['secret_question'])
34
+ @saved_form.secret_question = params['saved_form']['secret_question']
25
35
  @saved_form.populate_service_values(service)
26
36
  @saved_form.populate_session_values(session)
27
37
  if @saved_form.valid?
28
38
  # put in session until we have confirmed email address
39
+ @saved_form.secret_question = @saved_form.secret_question_text
29
40
  session[:saved_form] = @saved_form
30
41
  redirect_to '/save/email_confirmation'
31
42
  else
@@ -35,37 +46,137 @@ module MetadataPresenter
35
46
 
36
47
  def email_confirmation
37
48
  @saved_form = session[:saved_form]
38
- @email_confirmation = EmailConfirmation.new
49
+ @email_confirmation = EmailConfirmation.new(@saved_form['email'])
39
50
  end
40
51
 
41
52
  def confirm_email
42
- @email_confirmation = EmailConfirmation.new
43
- @email_confirmation.assign_attributes(confirmation_params[:email_confirmation], session['saved_form']['email'])
53
+ @email_confirmation = EmailConfirmation.new(confirmation_params[:email_confirmation])
44
54
 
45
55
  if @email_confirmation.valid?
56
+ session['saved_form']['email'] = @email_confirmation.email_confirmation
46
57
  response = save_form_progress
47
- if response.status != 200
58
+ if response.status == 500
48
59
  internal_server_error and return
49
60
  end
50
61
 
51
- # send_email(response.body['id'], confirmation_params[:email_confirmation])
62
+ payload = response.body.merge(email: @email_confirmation.email_confirmation).deep_symbolize_keys
63
+ create_save_and_return_submission(payload)
64
+
52
65
  redirect_to '/save/progress_saved'
53
66
  else
54
67
  render :email_confirmation, status: :unprocessable_entity
55
68
  end
56
69
  end
57
70
 
58
- # def return
59
- # uuid = params[:uuid]
60
- # response = get_saved_progress(uuid)
71
+ def return
72
+ response = get_saved_progress(get_uuid)
73
+
74
+ if response.status == 404
75
+ redirect_to '/record_error' and return
76
+ end
77
+
78
+ if response.status == 400
79
+ redirect_to '/record_failure' and return
80
+ end
81
+
82
+ if response.status == 422
83
+ redirect_to '/already_used' and return
84
+ end
85
+
86
+ @saved_form = SavedForm.new.from_json(response.body.to_json)
87
+ @resume_form = ResumeForm.new(@saved_form.secret_question)
88
+ end
89
+
90
+ def get_uuid
91
+ if params[:uuid].present?
92
+ return params[:uuid]
93
+ end
94
+
95
+ params[:resume_form][:uuid].presence
96
+ end
61
97
 
62
- # session[:user_id] = response['user_id']
63
- # session[:user_token] = response['user_token']
98
+ # rubocop:disable Style/RescueStandardError
99
+ def submit_secret_answer
100
+ response = get_saved_progress(get_uuid)
64
101
 
65
- # Rails.logger.info('returning to form')
66
- # Rails.logger.info('session')
67
- # redirect_to '/check-answers'
68
- # end
102
+ if response.status != 200
103
+ if response.status == 400
104
+ redirect_to '/record_failure' and return
105
+ end
106
+
107
+ redirect_to '/record_error' and return
108
+ end
109
+
110
+ @saved_form = SavedForm.new.from_json(response.body.to_json)
111
+ @resume_form = ResumeForm.new(@saved_form.secret_question)
112
+ @resume_form.secret_answer = resume_form_params[:resume_form][:secret_answer]
113
+ @resume_form.recorded_answer = @saved_form.secret_answer
114
+ @resume_form.attempts_remaining = 2 - @saved_form.attempts.to_i
115
+
116
+ if @resume_form.valid?
117
+ # redirect back to right place in form
118
+ session[:user_id] = @saved_form.user_id
119
+ session[:user_token] = @saved_form.user_token
120
+ session[:returning_slug] = @saved_form.page_slug
121
+
122
+ invalidate_record(@saved_form.id)
123
+
124
+ if @saved_form.service_version == service.version_id
125
+ redirect_to '/resume_progress' and return
126
+ else
127
+ redirect_to '/resume_from_start' and return
128
+ end
129
+ else
130
+ if @resume_form.attempts_remaining <= 0
131
+ begin
132
+ increment_record_counter(@saved_form.id)
133
+ rescue => e
134
+ Rails.logger.info(e)
135
+ redirect_to '/record_failure' and return
136
+ end
137
+ redirect_to '/record_failure' and return
138
+ end
139
+
140
+ increment_record_counter(@saved_form.id)
141
+
142
+ render :return, params: { uuid: @saved_form.id }
143
+ end
144
+ end
145
+ # rubocop:enable Style/RescueStandardError
146
+
147
+ def resume_progress
148
+ @user_data = load_user_data
149
+
150
+ @page ||= service.find_page_by_url('check-answers')
151
+
152
+ if @page
153
+ @page_answers = PageAnswers.new(@page, @answered_pages)
154
+
155
+ render template: 'metadata_presenter/save_and_return/resume_progress'
156
+ else
157
+ not_found
158
+ end
159
+ end
160
+
161
+ def save_progress
162
+ session['saved_form']['user_id'] = nil
163
+ session['saved_form']['user_token'] = nil
164
+ session['user_id'] = nil
165
+ session['user_token'] = nil
166
+ end
167
+
168
+ def answered_pages
169
+ TraversedPages.new(service, @user_data, @page).all
170
+ end
171
+
172
+ def pages_presenters
173
+ PageAnswersPresenter.map(
174
+ view: view_context,
175
+ pages: answered_pages,
176
+ answers: @user_data
177
+ )
178
+ end
179
+ helper_method :pages_presenters
69
180
 
70
181
  def secret_questions
71
182
  [
@@ -98,10 +209,19 @@ module MetadataPresenter
98
209
  )
99
210
  end
100
211
 
101
- private
212
+ def resume_form_params
213
+ params.permit(
214
+ { resume_form: %i[secret_answer uuid] },
215
+ :authenticity_token
216
+ )
217
+ end
218
+
219
+ def get_service_name
220
+ service.service_name
221
+ end
102
222
 
103
- def check_feature_flag
104
- redirect_to '/' and return if ENV['SAVE_AND_RETURN'] != 'enabled'
223
+ def label_text(text)
224
+ "<h2 class='govuk-heading-m'>#{text}</h2>"
105
225
  end
106
226
  end
107
227
  end
@@ -21,5 +21,16 @@ module MetadataPresenter
21
21
  super
22
22
  end
23
23
  end
24
+
25
+ def create_save_and_return_submission(payload)
26
+ # The runner is the only app that sends the save and return submission.
27
+ # and it is not needed on the editor app (editing & previewing).
28
+ # So in the Runner we defined the #create_save_and_return_submission in the parent
29
+ # controller and in the Editor we don't.
30
+ #
31
+ if defined?(super)
32
+ super
33
+ end
34
+ end
24
35
  end
25
36
  end
@@ -2,16 +2,12 @@ module MetadataPresenter
2
2
  class EmailConfirmation
3
3
  include ActiveModel::Model
4
4
 
5
- attr_accessor :email_confirmation,
6
- :session_email
5
+ attr_accessor :email_confirmation
7
6
 
8
7
  validates_with EmailConfirmationValidator
9
8
 
10
- def initialize; end
11
-
12
- def assign_attributes(email_confirmation, session_email)
13
- @email_confirmation = email_confirmation
14
- @session_email = session_email
9
+ def initialize(email)
10
+ self.email_confirmation = email
15
11
  end
16
12
  end
17
13
  end
@@ -19,11 +19,13 @@ module MetadataPresenter
19
19
  page.confirmation
20
20
  page.multiplequestions
21
21
  page.exit
22
+ save_and_return.resume_progress
22
23
  ].freeze
23
24
  END_OF_ROUTE_PAGES = %w[
24
25
  page.checkanswers
25
26
  page.confirmation
26
27
  page.exit
28
+ save_and_return.resume_progress
27
29
  ].freeze
28
30
 
29
31
  def editable_attributes
@@ -0,0 +1,16 @@
1
+ module MetadataPresenter
2
+ class ResumeForm
3
+ include ActiveModel::Model
4
+
5
+ attr_accessor :secret_question,
6
+ :secret_answer,
7
+ :recorded_answer,
8
+ :attempts_remaining
9
+
10
+ validates_with SecretAnswerValidator
11
+
12
+ def initialize(secret_question)
13
+ self.secret_question = secret_question
14
+ end
15
+ end
16
+ end
@@ -1,10 +1,13 @@
1
1
  module MetadataPresenter
2
2
  class SavedForm
3
3
  include ActiveModel::Model
4
+ include ActiveModel::Serializers::JSON
5
+
4
6
  validates_with SavedProgressValidator
5
7
 
6
8
  attr_accessor :email,
7
9
  :secret_question,
10
+ :secret_question_text,
8
11
  :secret_answer,
9
12
  :page_slug,
10
13
  :service_slug,
@@ -13,9 +16,13 @@ module MetadataPresenter
13
16
  :user_token,
14
17
  :user_data_payload,
15
18
  :attempts,
16
- :active
19
+ :active,
20
+ :id,
21
+ :created_at,
22
+ :updated_at
23
+
24
+ validates :secret_question, :secret_answer, :service_slug, :page_slug, :service_version, :user_id, :user_token, presence: { message: 'Enter an answer for "%{attribute}"' }, allow_blank: false
17
25
 
18
- validates :secret_question, :secret_answer, :service_slug, :page_slug, :service_version, :user_id, :user_token, presence: true, allow_blank: false
19
26
  def initialize; end
20
27
 
21
28
  def populate_param_values(params)
@@ -28,12 +35,21 @@ module MetadataPresenter
28
35
  def populate_session_values(session)
29
36
  self.user_id = session[:user_id]
30
37
  self.user_token = session[:user_token]
31
- self.user_data_payload = session[:user_data]
32
38
  end
33
39
 
34
40
  def populate_service_values(service)
35
41
  self.service_slug = service.service_slug
36
42
  self.service_version = service.version_id
37
43
  end
44
+
45
+ def attributes=(hash)
46
+ hash.each do |key, value|
47
+ send("#{key}=", value)
48
+ end
49
+ end
50
+
51
+ def attributes
52
+ instance_values
53
+ end
38
54
  end
39
55
  end
@@ -1,7 +1,8 @@
1
1
  class EmailConfirmationValidator < ActiveModel::Validator
2
2
  def validate(record)
3
- if record.email_confirmation != record.session_email
4
- record.errors.add(:email_confirmation, I18n.t('presenter.save_and_return.validation.email_not_matched'))
3
+ regex = URI::MailTo::EMAIL_REGEXP
4
+ if record.email_confirmation.match(regex).nil?
5
+ record.errors.add(:email_confirmation, I18n.t('presenter.save_and_return.validation.email'))
5
6
  end
6
7
  end
7
8
  end
@@ -4,5 +4,9 @@ class SavedProgressValidator < ActiveModel::Validator
4
4
  if record.email.match(regex).nil?
5
5
  record.errors.add(:email, I18n.t('presenter.save_and_return.validation.email'))
6
6
  end
7
+
8
+ if record.secret_answer.length > 100
9
+ record.errors.add(:secret_answer, I18n.t('presenter.save_and_return.validation.answer_too_long', attribute: 'Secret answer'))
10
+ end
7
11
  end
8
12
  end
@@ -0,0 +1,7 @@
1
+ class SecretAnswerValidator < ActiveModel::Validator
2
+ def validate(record)
3
+ if record.secret_answer.strip.downcase != record.recorded_answer.strip.downcase
4
+ record.errors.add(:secret_answer, I18n.t('presenter.save_and_return.validation.answer_not_matched', attempts: record.attempts_remaining))
5
+ end
6
+ end
7
+ end
@@ -84,9 +84,17 @@
84
84
  content_components: @page.supported_content_components
85
85
  } %>
86
86
 
87
- <button <%= 'disabled' if editable? %> data-prevent-double-click="true" class="fb-block fb-block-actions govuk-button" data-module="govuk-button" data-block-id="actions" data-block-type="actions">
88
- <%= t('presenter.actions.submit') -%>
89
- </button>
87
+ <div class="govuk-button-group">
88
+ <button <%= 'disabled' if editable? %> data-prevent-double-click="true" class="fb-block fb-block-actions govuk-button" data-module="govuk-button" data-block-id="actions" data-block-type="actions">
89
+ <%= t('presenter.actions.submit') -%></button>
90
+ <% if save_and_return_enabled? %>
91
+ <% if editor_preview? || editable? %>
92
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later', disabled: true %>
93
+ <% else %>
94
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later'%>
95
+ <% end %>
96
+ <% end %>
97
+ </div>
90
98
  <% end %>
91
99
 
92
100
  </div>
@@ -25,7 +25,15 @@
25
25
  content_components: @page.supported_content_components
26
26
  } %>
27
27
 
28
- <%= f.govuk_submit(disabled: editable?) %>
28
+ <div class="govuk-button-group">
29
+ <%= f.govuk_submit(disabled: editable?) %>
30
+ <% if save_and_return_enabled? %>
31
+ <% if editor_preview? || editable? %>
32
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later', disabled: true %>
33
+ <% else %>
34
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later'%>
35
+ <% end %>
36
+ <% end %> </div>
29
37
  <% end %>
30
38
  </div>
31
39
  </div>
@@ -17,8 +17,15 @@
17
17
  content_components: @page.supported_content_components
18
18
  }
19
19
  %>
20
-
21
- <%= f.govuk_submit(disabled: editable?) %>
20
+ <div class="govuk-button-group">
21
+ <%= f.govuk_submit(disabled: editable?) %>
22
+ <% if save_and_return_enabled? %>
23
+ <% if editor_preview? || editable? %>
24
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later', disabled: true %>
25
+ <% else %>
26
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later'%>
27
+ <% end %>
28
+ <% end %> </div>
22
29
  <% end %>
23
30
  </div>
24
31
  </div>
@@ -20,7 +20,17 @@
20
20
  </div>
21
21
  <% end %>
22
22
 
23
- <%= f.govuk_submit(disabled: editable?) %> <% if ENV['SAVE_AND_RETURN'] == 'enabled' %><a href="<%= save_path(:page_slug=>request.env['PATH_INFO']) %>" class="govuk-button" data-module="govuk-button" data-component="save-button"><%= t('presenter.save_and_return.save') %></a><% end %>
23
+ <div class="govuk-button-group">
24
+ <%= f.govuk_submit(disabled: editable?) %>
25
+
26
+ <% if save_and_return_enabled? %>
27
+ <% if editor_preview? || editable? %>
28
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later', disabled: true %>
29
+ <% else %>
30
+ <%= button_to t('presenter.save_and_return.save'), '/', params: { page_slug:request.env['PATH_INFO'] }, method: :post, class: "govuk-button govuk-button--secondary", name: 'save_for_later'%>
31
+ <% end %>
32
+ <% end %>
33
+ </div>
24
34
  <% end %>
25
35
  </div>
26
36
  </div>
@@ -1,22 +1,25 @@
1
1
  <div class="fb-main-grid-wrapper">
2
2
  <div class="govuk-grid-row">
3
3
  <div class="govuk-grid-column-two-thirds">
4
- <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.confirm_email.heading') %></h1>
5
- <%= form_for @email_confirmation do |f| %>
6
- <%= f.govuk_error_summary %>
7
- <div class="govuk-form-group">
8
- <%=
9
- f.govuk_email_field :email_confirmation,
10
- label: { text: t('presenter.save_and_return.show.email_confirmation') },
11
- name: "email_confirmation",
12
- spellcheck: "false",
13
- autocomplete: "email"
14
- %>
15
- </div>
16
-
17
- <p class="mojf-settings-screen__description"><%= t('presenter.save_and_return.confirm_email.description') %></p>
18
-
19
- <%= f.govuk_submit t('presenter.save_and_return.show.continue') %><% end %> <%= link_to t('presenter.save_and_return.show.cancel'), page_slug, class: "govuk-button govuk-button--secondary" %>
4
+ <a class="govuk-back-link" href="<%= :back %>"><%= t('presenter.back') %></a>
5
+ <%= form_for @email_confirmation do |f| %>
6
+ <%= f.govuk_error_summary %>
7
+ <div class="govuk-form-group">
8
+ <%=
9
+ f.govuk_email_field :email_confirmation,
10
+ label: { size: 'l', text: t('presenter.save_and_return.confirm_email.heading') },
11
+ name: "email_confirmation",
12
+ spellcheck: "false",
13
+ autocomplete: "email"
14
+ %>
15
+ </div>
16
+
17
+ <p class="mojf-settings-screen__description"><%= t('presenter.save_and_return.confirm_email.description') %></p>
18
+ <br/>
19
+ <div class="govuk-button-group">
20
+ <%= f.govuk_submit t('presenter.save_and_return.show.continue') %> <%= link_to t('presenter.save_and_return.show.cancel'), page_slug, class: "govuk-button govuk-button--secondary" %>
21
+ <div class="govuk-button-group">
22
+ <% end %>
20
23
  </div>
21
24
  </div>
22
25
  </div>
@@ -0,0 +1,9 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.errors.generic_problem.heading') %></h1>
5
+ <p><%= t('presenter.save_and_return.resume.errors.generic_problem.info_1') %></p>
6
+ <p><%= t('presenter.save_and_return.resume.errors.generic_problem.info_2') %></p>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.errors.failure.heading') %></h1>
5
+ <p><%= t('presenter.save_and_return.resume.errors.failure.info_1') %></p>
6
+ <p><%= t('presenter.save_and_return.resume.errors.failure.info_2') %></p>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.errors.expired.heading') %></h1>
5
+ <p><%= t('presenter.save_and_return.resume.errors.expired.info_1') %></p>
6
+ <p><%= t('presenter.save_and_return.resume.errors.expired.info_2') %></p>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.errors.link_used.heading') %></h1>
5
+ <p><%= t('presenter.save_and_return.resume.errors.link_used.info_1') %></p>
6
+ <p><%= t('presenter.save_and_return.resume.errors.link_used.info_2') %></p>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.from_start.heading', service_name: service.service_name) %></h1>
5
+ <p class="govuk-hint"><%= t('presenter.save_and_return.resume.from_start.info_1') %></p>
6
+ <br/>
7
+ <p class="govuk-hint"><%= t('presenter.save_and_return.resume.from_start.info_2') %></p>
8
+ <%= link_to t('presenter.save_and_return.resume.from_start.continue'), root_path, class: "govuk-button" %>
9
+ </div>
10
+ </div>
11
+ </div>
@@ -0,0 +1,50 @@
1
+ <div class="fb-main-grid-wrapper" data-fb-pagetype="resume_progress">
2
+ <h1 class="fb-editable govuk-heading-xl"
3
+ data-fb-content-type="element">
4
+ <%= t('presenter.save_and_return.resume.progress.heading', service_name: get_service_name) %>
5
+ </h1>
6
+ <div class="govuk-grid-row">
7
+ <div class="govuk-grid-column-two-thirds">
8
+ <p><%= t('presenter.save_and_return.resume.progress.content_1') %></p>
9
+ <p><%= t('presenter.save_and_return.resume.progress.content_2') %></p>
10
+ <%= form_for @page, url: reserved_submissions_path, html: { id: 'answers-form' } do |f| %>
11
+ <dl class="fb-block fb-block-answers govuk-summary-list">
12
+ <% pages_presenters.each do |page_answers_presenters| %>
13
+ <% page_answers_presenters.each_with_index do |page_answers_presenter, index| %>
14
+
15
+ <% if !page_answers_presenter.answer.empty? %>
16
+
17
+ <div class="govuk-summary-list__row">
18
+ <dt class="govuk-summary-list__key">
19
+ <%= page_answers_presenter.humanised_title %>
20
+ </dt>
21
+
22
+ <dd class="govuk-summary-list__value">
23
+ <%= page_answers_presenter.answer %>
24
+ </dd>
25
+ <dd class="govuk-summary-list__actions">
26
+ <%= link_to(
27
+ editable? ? '#' : page_answers_presenter.url,
28
+ class: 'govuk-link'
29
+ ) do %>
30
+ Change<span class="govuk-visually-hidden"> Your answer for <%= page_answers_presenter.humanised_title %></span>
31
+ <% end %>
32
+ </dd>
33
+ </div>
34
+
35
+ <% if page_answers_presenter.last_multiple_question?(index, page_answers_presenters.size) %>
36
+ <% end %>
37
+ </dl>
38
+ <dl class="fb-block fb-block-answers govuk-summary-list">
39
+ <% end %>
40
+ <% end %>
41
+ <% end %>
42
+ </dl>
43
+
44
+ <div class="govuk-button-group">
45
+ <%= link_to t('presenter.save_and_return.resume.progress.continue'), page_slug, class: "govuk-button" %> <a href="<%= save_path(:page_slug=>page_slug) %>" class="govuk-button govuk-button--secondary" data-module="govuk-button" data-component="save-button"><%= t('presenter.save_and_return.save') %></a>
46
+ </div>
47
+ <% end %>
48
+ </div>
49
+ </div>
50
+ </div>
@@ -0,0 +1,26 @@
1
+ <div class="fb-main-grid-wrapper">
2
+ <div class="govuk-grid-row">
3
+ <div class="govuk-grid-column-two-thirds">
4
+ <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.resume.heading', service_name: get_service_name) %></h1>
5
+ <p><%= t('presenter.save_and_return.resume.content') %></p>
6
+ <%= form_for @resume_form do |f| %>
7
+ <%= f.govuk_error_summary %>
8
+ <%= f.hidden_field(:uuid, value: get_uuid) %>
9
+ <div class="govuk-form-group">
10
+ <%=
11
+ f.govuk_text_field :secret_answer,
12
+ label: { text: to_html(label_text(f.object.secret_question)) }
13
+ %>
14
+ </div>
15
+
16
+ <div class="govuk-warning-text">
17
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
18
+ <strong class="govuk-warning-text__text">
19
+ <span class="govuk-warning-text__assistive">Warning</span>
20
+ <%= t('presenter.save_and_return.resume.information') %>
21
+ </strong>
22
+ </div>
23
+ <%= f.govuk_submit t('presenter.save_and_return.resume.continue') %><% end %>
24
+ </div>
25
+ </div>
26
+ </div>
@@ -3,11 +3,11 @@
3
3
  <div class="govuk-grid-column-two-thirds">
4
4
  <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.saved.heading') %></h1>
5
5
  <p class="mojf-settings-screen__description"><%= t('presenter.save_and_return.saved.success', email: confirmed_email) %></p>
6
- <p class="govuk-hint"><%= t('presenter.save_and_return.saved.info_1') %></p>
6
+ <p><%= t('presenter.save_and_return.saved.info_1') %></p>
7
7
  <br/>
8
- <p class="govuk-hint"><%= t('presenter.save_and_return.saved.info_2') %></p>
8
+ <p><%= t('presenter.save_and_return.saved.info_2') %></p>
9
9
  <br/>
10
- <p class="govuk-hint"><%= t('presenter.save_and_return.saved.info_3') %></p>
10
+ <p><%= t('presenter.save_and_return.saved.info_3') %></p>
11
11
  </div>
12
12
  </div>
13
13
  </div>
@@ -4,41 +4,44 @@
4
4
  <h1 id="page-heading" class="govuk-heading-xl"><%= t('presenter.save_and_return.show.heading') %></h1>
5
5
  <p class="mojf-settings-screen__description"><%= t('presenter.save_and_return.show.description') %></p>
6
6
 
7
- <%= form_for @saved_form do |f| %>
8
- <%= f.govuk_error_summary %>
9
- <div class="govuk-form-group">
10
- <%= f.hidden_field(:page_slug, value: page_slug) %>
11
- <%=
12
- f.govuk_email_field :email,
13
- label: { text: t('presenter.save_and_return.show.email') },
14
- hint: {
15
- data: { "fb-default-text" => default_text('hint') },
16
- text: t('presenter.save_and_return.show.email_hint')
17
- },
18
- name: "email",
19
- spellcheck: "false",
20
- autocomplete: "email"
21
- %>
22
- <%=
23
- f.govuk_collection_radio_buttons :secret_question,
24
- secret_questions,
25
- :id,
26
- :name,
27
- legend: { text: t('presenter.save_and_return.show.secret_question') },
28
- hint: {
29
- data: { "fb-default-text" => default_text('hint') },
30
- text: t('presenter.save_and_return.show.secret_question_hint')
31
- },
32
- bold_labels: false
33
- %>
34
- <%=
35
- f.govuk_text_field :secret_answer,
36
- label: { text: t('presenter.save_and_return.show.secret_answer') },
7
+ <%= form_for @saved_form do |f| %>
8
+ <%= f.govuk_error_summary %>
9
+ <div class="govuk-form-group">
10
+ <%= f.hidden_field(:page_slug, value: page_slug) %>
11
+ <%=
12
+ f.govuk_email_field :email,
13
+ label: { text: to_html(label_text(t('presenter.save_and_return.show.email'))) },
14
+ hint: {
15
+ data: { "fb-default-text" => default_text('hint') },
16
+ text: t('presenter.save_and_return.show.email_hint')
17
+ },
18
+ name: "email",
19
+ spellcheck: "false",
20
+ autocomplete: "email"
21
+ %>
22
+ <%=
23
+ f.govuk_collection_radio_buttons :secret_question,
24
+ secret_questions,
25
+ :id,
26
+ :name,
27
+ legend: { text: t('presenter.save_and_return.show.secret_question') },
28
+ hint: {
29
+ data: { "fb-default-text" => default_text('hint') },
30
+ text: t('presenter.save_and_return.show.secret_question_hint')
31
+ },
32
+ bold_labels: false
33
+ %>
34
+ <%=
35
+ f.govuk_text_field :secret_answer,
36
+ label: { text: to_html(label_text(t('presenter.save_and_return.show.secret_answer'))) },
37
37
  name: "secret_answer"
38
- %>
39
- </div>
40
-
41
- <%= f.govuk_submit t('presenter.save_and_return.show.continue') %><% end %> <%= link_to t('presenter.save_and_return.show.cancel'), page_slug, class: "govuk-button govuk-button--secondary" %>
38
+ %>
39
+ </div>
40
+
41
+ <div class="govuk-button-group">
42
+ <%= f.govuk_submit t('presenter.save_and_return.show.continue') %> <%= link_to t('presenter.save_and_return.show.cancel'), page_slug, class: "govuk-button govuk-button--secondary" %>
43
+ </div>
44
+ <% end %>
42
45
  </div>
43
46
  </div>
44
47
  </div>
@@ -1,5 +1,6 @@
1
1
  en:
2
2
  presenter:
3
+ back: 'Back'
3
4
  actions:
4
5
  start: Start now
5
6
  continue: Continue
@@ -42,7 +43,7 @@ en:
42
43
  heading: 'Save for later'
43
44
  description: 'We will send you a one-off link that you can use to resume this form within 28 days.'
44
45
  email: 'Email address'
45
- email_hint: 'Where we will send the link'
46
+ email_hint: 'We will only use this to send you a link to your form'
46
47
  secret_question: 'Pick a security question'
47
48
  secret_question_hint: 'We will use this to verify your identity when you return'
48
49
  secret_answer: 'The answer to your security question'
@@ -60,10 +61,44 @@ en:
60
61
  validation:
61
62
  email: 'Enter an email address in the correct format, like name@example.com'
62
63
  email_not_matched: 'Does not match'
64
+ answer_not_matched: 'Your answer is incorrect. You have %{attempts} attempts remaining.'
65
+ answer_too_long: 'Your answer for %{attribute} must be 100 characters or fewer.'
63
66
  secret_questions:
64
67
  one: "What is your mother's maiden name?"
65
68
  two: 'What is the last name of your favourite teacher?'
66
69
  three: 'What is the name of the hospital where you were born?'
70
+ resume:
71
+ heading: "Continue with \"%{service_name}\""
72
+ continue: 'Continue'
73
+ content: 'To retrieve your information, enter the answer to your security question that you set when saving your progress.'
74
+ information: 'This will use up your save link. To save your progress again, you will need to repeat the save process and generate another link.'
75
+ errors:
76
+ generic_problem:
77
+ heading: 'There is a problem with your link'
78
+ info_1: 'Please try again. If you copied and pasted the link into your browser, check you copied the entire link.'
79
+ info_2: 'If this problem persists, you will need to start the form again. Your saved answers will be securely deleted after 28 days.'
80
+ expired:
81
+ heading: 'Your link has expired'
82
+ info_1: 'It has been more than 28 days since you saved your progress on this form and the link is no longer valid.'
83
+ info_2: 'Your saved answers have been be securely deleted.'
84
+ link_used:
85
+ heading: 'That link has already been used'
86
+ info_1: 'Links to resume a form only work once. If you have saved your progress more than once, check for a more recent link.'
87
+ info_2: 'Otherwise, you will need to start the form again. Your saved answers will be securely deleted after 28 days.'
88
+ failure:
89
+ heading: 'Your information cannot be retrieved'
90
+ info_1: 'The answer to your security question was incorrect and you have run out of attempts to retrieve your information.'
91
+ info_2: 'You will need to start the form again. Your saved answers will be securely deleted.'
92
+ from_start:
93
+ heading: "\"%{service_name}\" has been updated"
94
+ info_1: 'Your information has been successfully retrieved. However, the form has been updated since your last visit.'
95
+ info_2: 'Please check from the beginning in case anything has changed, such as new requirements or questions.'
96
+ continue: 'Continue'
97
+ progress:
98
+ heading: '%{service_name}'
99
+ content_1: 'You have sucessfuly retrieved your saved information.'
100
+ content_2: 'Here are the answers you have provided so far.'
101
+ continue: 'Continue'
67
102
  footer:
68
103
  cookies:
69
104
  heading: "Cookies"
data/config/routes.rb CHANGED
@@ -15,7 +15,14 @@ MetadataPresenter::Engine.routes.draw do
15
15
  get 'save/email_confirmation', to: 'save_and_return#email_confirmation'
16
16
  post 'email_confirmations', to: 'save_and_return#confirm_email'
17
17
  get 'save/progress_saved', to: 'save_and_return#save_progress'
18
- # get 'return/:service_slug/:uuid', to: 'save_and_return#return'
18
+ get '/return/:uuid', to: 'save_and_return#return'
19
+ post 'resume_forms', to: 'save_and_return#submit_secret_answer'
20
+ get 'record_error', to: 'save_and_return#record_error'
21
+ get 'record_failure', to: 'save_and_return#record_failure'
22
+ get 'expired', to: 'save_and_return#record_link_expired'
23
+ get 'already_used', to: 'save_and_return#record_link_used'
24
+ get 'resume_from_start', to: 'save_and_return#resume_from_start'
25
+ get 'resume_progress', to: 'save_and_return#resume_progress'
19
26
 
20
27
  post '/', to: 'answers#create'
21
28
  match '*path', to: 'answers#create', via: :post
@@ -1,3 +1,3 @@
1
1
  module MetadataPresenter
2
- VERSION = '2.18.7'.freeze
2
+ VERSION = '2.19.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metadata_presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.7
4
+ version: 2.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - MoJ Forms
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-28 00:00:00.000000000 Z
11
+ date: 2023-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_design_system_formbuilder
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "<"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 6.2.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: sassc-rails
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 2.1.2
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '='
87
+ - !ruby/object:Gem::Version
88
+ version: 2.1.2
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: better_errors
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -287,6 +301,7 @@ files:
287
301
  - app/models/metadata_presenter/page_answers.rb
288
302
  - app/models/metadata_presenter/page_warning.rb
289
303
  - app/models/metadata_presenter/previous_page.rb
304
+ - app/models/metadata_presenter/resume_form.rb
290
305
  - app/models/metadata_presenter/route.rb
291
306
  - app/models/metadata_presenter/row_number.rb
292
307
  - app/models/metadata_presenter/saved_form.rb
@@ -325,6 +340,7 @@ files:
325
340
  - app/validators/metadata_presenter/virus_scan_validator.rb
326
341
  - app/validators/metadata_presenter/word_count.rb
327
342
  - app/validators/saved_progress_validator.rb
343
+ - app/validators/secret_answer_validator.rb
328
344
  - app/views/errors/404.html
329
345
  - app/views/errors/500.html
330
346
  - app/views/layouts/metadata_presenter/application.html.erb
@@ -365,6 +381,13 @@ files:
365
381
  - app/views/metadata_presenter/page/standalone.html.erb
366
382
  - app/views/metadata_presenter/page/start.html.erb
367
383
  - app/views/metadata_presenter/save_and_return/email_confirmation.html.erb
384
+ - app/views/metadata_presenter/save_and_return/record_error.html.erb
385
+ - app/views/metadata_presenter/save_and_return/record_failure.html.erb
386
+ - app/views/metadata_presenter/save_and_return/record_link_expired.html.erb
387
+ - app/views/metadata_presenter/save_and_return/record_link_used.html.erb
388
+ - app/views/metadata_presenter/save_and_return/resume_from_start.html.erb
389
+ - app/views/metadata_presenter/save_and_return/resume_progress.html.erb
390
+ - app/views/metadata_presenter/save_and_return/return.html.erb
368
391
  - app/views/metadata_presenter/save_and_return/save_progress.html.erb
369
392
  - app/views/metadata_presenter/save_and_return/show.html.erb
370
393
  - app/views/metadata_presenter/session/_timeout_fallback.html.erb