metadata_presenter 2.18.6 → 2.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) 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/errors/404.html +6 -66
  15. data/app/views/metadata_presenter/page/checkanswers.html.erb +10 -3
  16. data/app/views/metadata_presenter/page/content.html.erb +9 -1
  17. data/app/views/metadata_presenter/page/multiplequestions.html.erb +9 -2
  18. data/app/views/metadata_presenter/page/singlequestion.html.erb +11 -1
  19. data/app/views/metadata_presenter/save_and_return/email_confirmation.html.erb +19 -16
  20. data/app/views/metadata_presenter/save_and_return/record_error.html.erb +9 -0
  21. data/app/views/metadata_presenter/save_and_return/record_failure.html.erb +9 -0
  22. data/app/views/metadata_presenter/save_and_return/record_link_expired.html.erb +9 -0
  23. data/app/views/metadata_presenter/save_and_return/record_link_used.html.erb +9 -0
  24. data/app/views/metadata_presenter/save_and_return/resume_from_start.html.erb +11 -0
  25. data/app/views/metadata_presenter/save_and_return/resume_progress.html.erb +50 -0
  26. data/app/views/metadata_presenter/save_and_return/return.html.erb +26 -0
  27. data/app/views/metadata_presenter/save_and_return/save_progress.html.erb +3 -3
  28. data/app/views/metadata_presenter/save_and_return/show.html.erb +37 -34
  29. data/config/locales/en.yml +36 -1
  30. data/config/routes.rb +8 -1
  31. data/lib/metadata_presenter/version.rb +1 -1
  32. metadata +25 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d8abb52822dee49505be01d36fcf044cdf1428e5f0b4858c79e955f735b4b85
4
- data.tar.gz: 0405e28449fd23187d2304811b3c47f782d1b17d901d5bc0ed36d8045f9f59a7
3
+ metadata.gz: d631aa0b87b76c112abb7c67a554da2cd7a7292c234b078590647ad455740bb7
4
+ data.tar.gz: ae914cf8380a19707d30e98700a4bf5bb884f81c5b547b0a03cf9f96971a47ec
5
5
  SHA512:
6
- metadata.gz: 37e4e33318dfa07794042dddedc4141e759a1e8dbf7edac35322f4c9633a9b4513dbcd304b8641fc7e70677fdcd66c1f43f01dead8b1b0236061f509bfde9187
7
- data.tar.gz: 1adf2259573f08bcb44ba00bd6b6e4ffc635332ccc25ff556a50f8cb9d7affe93eb96b43cbd5ca10215385480155f0e69656ef9ebc7ac0a797f94edf14cb307c
6
+ metadata.gz: 936ac69f86688086114f8cda9b8042150e17885cef1b30e4d0b41a7cfd9e631911c2c863143ccf8a708b857ff0d54d38bb02e926526488e5b9b1fa0c131af4aa
7
+ data.tar.gz: 86b7554f3d012c0d9d70babcf531d2afc5923424bccf418ad6958e5f0fa72cd9dc2997ec7dfcdf441a506d87ab6eb393a09f0d6cb628e640d63c9fa935efe386
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
@@ -1,67 +1,7 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>The page you were looking for doesn't exist (404)</title>
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <style>
7
- .rails-default-error-page {
8
- background-color: #EFEFEF;
9
- color: #2E2F30;
10
- text-align: center;
11
- font-family: arial, sans-serif;
12
- margin: 0;
13
- }
1
+ <div>
2
+ <h1>Page not found</h1>
3
+ <p>If you typed the web address, check it is correct.</p>
4
+ <p>If you pasted the web address, check you copied the entire address.</p>
5
+ <p>If the problem persists, <a href="https://moj-forms.service.justice.gov.uk/contact/">contact the MoJ Forms team.</a></p>
6
+ </div>
14
7
 
15
- .rails-default-error-page div.dialog {
16
- width: 95%;
17
- max-width: 33em;
18
- margin: 4em auto 0;
19
- }
20
-
21
- .rails-default-error-page div.dialog > div {
22
- border: 1px solid #CCC;
23
- border-right-color: #999;
24
- border-left-color: #999;
25
- border-bottom-color: #BBB;
26
- border-top: #B00100 solid 4px;
27
- border-top-left-radius: 9px;
28
- border-top-right-radius: 9px;
29
- background-color: white;
30
- padding: 7px 12% 0;
31
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
- }
33
-
34
- .rails-default-error-page h1 {
35
- font-size: 100%;
36
- color: #730E15;
37
- line-height: 1.5em;
38
- }
39
-
40
- .rails-default-error-page div.dialog > p {
41
- margin: 0 0 1em;
42
- padding: 1em;
43
- background-color: #F7F7F7;
44
- border: 1px solid #CCC;
45
- border-right-color: #999;
46
- border-left-color: #999;
47
- border-bottom-color: #999;
48
- border-bottom-left-radius: 4px;
49
- border-bottom-right-radius: 4px;
50
- border-top-color: #DADADA;
51
- color: #666;
52
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
- }
54
- </style>
55
- </head>
56
-
57
- <body class="rails-default-error-page">
58
- <!-- This file lives in public/404.html -->
59
- <div class="dialog">
60
- <div>
61
- <h1>The page you were looking for doesn't exist.</h1>
62
- <p>You may have mistyped the address or the page may have moved.</p>
63
- </div>
64
- <p>If you are the application owner check the logs for more information.</p>
65
- </div>
66
- </body>
67
- </html>
@@ -84,9 +84,16 @@
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') -%>
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 %> </div>
90
97
  <% end %>
91
98
 
92
99
  </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.6'.freeze
2
+ VERSION = '2.19'.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.6
4
+ version: '2.19'
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-27 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