metadata_presenter 1.3.2 → 1.7.0
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.
- checksums.yaml +4 -4
- data/README.md +12 -0
- data/app/controllers/metadata_presenter/answers_controller.rb +4 -2
- data/app/controllers/metadata_presenter/change_answer_controller.rb +1 -1
- data/app/controllers/metadata_presenter/engine_controller.rb +12 -7
- data/app/models/metadata_presenter/component.rb +5 -1
- data/app/models/metadata_presenter/condition.rb +13 -0
- data/app/models/metadata_presenter/criteria.rb +25 -0
- data/app/models/metadata_presenter/evaluate_conditions.rb +37 -0
- data/app/models/metadata_presenter/flow.rb +21 -0
- data/app/models/metadata_presenter/next_page.rb +53 -8
- data/app/models/metadata_presenter/page.rb +8 -0
- data/app/models/metadata_presenter/page_answers.rb +2 -0
- data/app/models/metadata_presenter/previous_page.rb +38 -0
- data/app/models/metadata_presenter/service.rb +12 -4
- data/app/models/metadata_presenter/traversed_pages.rb +40 -0
- data/app/operators/metadata_presenter/base_operator.rb +20 -0
- data/app/operators/metadata_presenter/is_answered_operator.rb +7 -0
- data/app/operators/metadata_presenter/is_not_answered_operator.rb +7 -0
- data/app/operators/metadata_presenter/is_not_operator.rb +11 -0
- data/app/operators/metadata_presenter/is_operator.rb +11 -0
- data/app/operators/metadata_presenter/operator.rb +29 -0
- data/config/initializers/inflections.rb +3 -0
- data/fixtures/branching.json +1047 -0
- data/lib/metadata_presenter/version.rb +1 -1
- data/lib/tasks/metadata_presenter_tasks.rake +89 -4
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0817e0fd8648eed9b10a3b5244e6933f8492805f76843db92ae17f3fab3adf36'
|
4
|
+
data.tar.gz: a31749c039cd29a2c836959a47fb2801bb10418520f022edd6783cc78913a6c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad688abaf732349b401eabf92390c23db5760062d5b23bf36aca96431cfa3dfbbb2e7409ca2daf405828f4f65123225f1b3889ef014c20c121c333c6c23bf7ed
|
7
|
+
data.tar.gz: 31bd7f7e65d82476b75d6b6dc6d608b1ba30dab6e3b5b5c23b7ec539d08682ab0ed3a5ca278b5067f3550d6fd867551d3b8fb91fb2eaceda9f04787d2df86f4f
|
data/README.md
CHANGED
@@ -83,3 +83,15 @@ service.
|
|
83
83
|
## Generate documentation
|
84
84
|
|
85
85
|
Run `rake doc` and open the doc/index.html
|
86
|
+
|
87
|
+
## Flow diagrams
|
88
|
+
|
89
|
+
You can generate flow diagrams calling a rake task:
|
90
|
+
|
91
|
+
```
|
92
|
+
brew install graphviz
|
93
|
+
SERVICE_METADATA="some-form-metadata" rails metadata:flow
|
94
|
+
```
|
95
|
+
|
96
|
+
This will generate an image with the flow for that metadata. Open that image
|
97
|
+
and profit!
|
@@ -25,10 +25,12 @@ module MetadataPresenter
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def redirect_to_next_page
|
28
|
-
next_page = NextPage.new(
|
28
|
+
next_page = NextPage.new(
|
29
|
+
service: service,
|
29
30
|
session: session,
|
31
|
+
user_data: load_user_data,
|
30
32
|
current_page_url: page_url
|
31
|
-
)
|
33
|
+
).find
|
32
34
|
|
33
35
|
if next_page.present?
|
34
36
|
redirect_to_page next_page.url
|
@@ -6,14 +6,19 @@ module MetadataPresenter
|
|
6
6
|
default_form_builder GOVUKDesignSystemFormBuilder::FormBuilder
|
7
7
|
|
8
8
|
def back_link
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
previous_page = PreviousPage.new(
|
10
|
+
service: service,
|
11
|
+
user_data: load_user_data,
|
12
12
|
current_page: @page,
|
13
|
-
referrer: request.
|
14
|
-
)
|
15
|
-
|
16
|
-
|
13
|
+
referrer: request.referrer
|
14
|
+
).page
|
15
|
+
|
16
|
+
if previous_page
|
17
|
+
@back_link ||= File.join(
|
18
|
+
request.script_name,
|
19
|
+
previous_page.url
|
20
|
+
)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
helper_method :back_link
|
19
24
|
|
@@ -8,7 +8,7 @@ class MetadataPresenter::Component < MetadataPresenter::Metadata
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def items
|
11
|
-
metadata.items.map do |item|
|
11
|
+
Array(metadata.items).map do |item|
|
12
12
|
MetadataPresenter::Item.new(item, editor: editor?)
|
13
13
|
end
|
14
14
|
end
|
@@ -20,4 +20,8 @@ class MetadataPresenter::Component < MetadataPresenter::Metadata
|
|
20
20
|
def upload?
|
21
21
|
type == 'upload'
|
22
22
|
end
|
23
|
+
|
24
|
+
def find_item_by_uuid(uuid)
|
25
|
+
items.find { |item| item.uuid == uuid }
|
26
|
+
end
|
23
27
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Condition < MetadataPresenter::Metadata
|
3
|
+
def ==(other)
|
4
|
+
metadata.to_h.deep_symbolize_keys == other.metadata.to_h.deep_symbolize_keys
|
5
|
+
end
|
6
|
+
|
7
|
+
def criterias
|
8
|
+
Array(metadata.criterias).map do |criteria|
|
9
|
+
MetadataPresenter::Criteria.new(criteria)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Criteria < MetadataPresenter::Metadata
|
3
|
+
attr_accessor :service
|
4
|
+
|
5
|
+
def ==(other)
|
6
|
+
metadata == other.metadata
|
7
|
+
end
|
8
|
+
|
9
|
+
def criteria_page
|
10
|
+
service.find_page_by_uuid(page)
|
11
|
+
end
|
12
|
+
|
13
|
+
def criteria_component
|
14
|
+
criteria_page.find_component_by_uuid(component)
|
15
|
+
end
|
16
|
+
|
17
|
+
def criteria_field
|
18
|
+
criteria_component.find_item_by_uuid(field)
|
19
|
+
end
|
20
|
+
|
21
|
+
def field_label
|
22
|
+
criteria_field['label'] if criteria_field
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class EvaluateConditions
|
3
|
+
include ActiveModel::Model
|
4
|
+
attr_accessor :service, :flow, :user_data
|
5
|
+
|
6
|
+
def page
|
7
|
+
evaluated_page_uuid = page_uuid || flow.default_next
|
8
|
+
|
9
|
+
service.find_page_by_uuid(evaluated_page_uuid)
|
10
|
+
end
|
11
|
+
|
12
|
+
def page_uuid
|
13
|
+
@results ||= conditions.map do |condition|
|
14
|
+
evaluated_criterias = condition.criterias.map do |criteria|
|
15
|
+
criteria.service = service
|
16
|
+
|
17
|
+
Operator.new(
|
18
|
+
criteria.operator
|
19
|
+
).evaluate(
|
20
|
+
criteria.field_label,
|
21
|
+
user_data[criteria.criteria_component.id]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
if condition.condition_type == 'or' && evaluated_criterias.any?
|
26
|
+
condition.next
|
27
|
+
elsif evaluated_criterias.all?
|
28
|
+
condition.next
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@results.flatten.compact.first
|
33
|
+
end
|
34
|
+
|
35
|
+
delegate :conditions, to: :flow
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Flow < MetadataPresenter::Metadata
|
3
|
+
def branch?
|
4
|
+
type == 'branch'
|
5
|
+
end
|
6
|
+
|
7
|
+
def default_next
|
8
|
+
metadata['next']['default']
|
9
|
+
end
|
10
|
+
|
11
|
+
def conditions
|
12
|
+
Array(metadata['next']['conditions']).map do |condition_metadata|
|
13
|
+
Condition.new(condition_metadata)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def group_by_page
|
18
|
+
conditions.group_by(&:next)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,18 +1,63 @@
|
|
1
1
|
module MetadataPresenter
|
2
2
|
class NextPage
|
3
|
-
|
3
|
+
include ActiveModel::Model
|
4
|
+
attr_accessor :service, :session, :user_data, :current_page_url
|
4
5
|
|
5
|
-
def
|
6
|
-
|
7
|
-
end
|
6
|
+
def find
|
7
|
+
return check_answers_page if return_to_check_your_answer?
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
service.
|
9
|
+
if conditions?
|
10
|
+
evaluate_conditions
|
11
|
+
elsif current_page_flow.present?
|
12
|
+
service.find_page_by_uuid(current_page_flow.default_next)
|
13
13
|
else
|
14
14
|
service.next_page(from: current_page_url)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def check_answers_page
|
21
|
+
session[:return_to_check_your_answer] = nil
|
22
|
+
service.pages.find { |page| page.type == 'page.checkanswers' }
|
23
|
+
end
|
24
|
+
|
25
|
+
def return_to_check_your_answer?
|
26
|
+
session[:return_to_check_your_answer].present?
|
27
|
+
end
|
28
|
+
|
29
|
+
def conditions?
|
30
|
+
current_page_flow.present? &&
|
31
|
+
next_flow.present? &&
|
32
|
+
next_flow_branch_object?
|
33
|
+
end
|
34
|
+
|
35
|
+
def evaluate_conditions
|
36
|
+
EvaluateConditions.new(
|
37
|
+
service: service,
|
38
|
+
flow: next_flow,
|
39
|
+
user_data: user_data
|
40
|
+
).page
|
41
|
+
end
|
42
|
+
|
43
|
+
def current_page
|
44
|
+
service.find_page_by_url(current_page_url)
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_page_uuid
|
48
|
+
current_page.uuid
|
49
|
+
end
|
50
|
+
|
51
|
+
def current_page_flow
|
52
|
+
service.flow(current_page_uuid)
|
53
|
+
end
|
54
|
+
|
55
|
+
def next_flow
|
56
|
+
service.flow(current_page_flow.default_next)
|
57
|
+
end
|
58
|
+
|
59
|
+
def next_flow_branch_object?
|
60
|
+
next_flow.branch?
|
61
|
+
end
|
17
62
|
end
|
18
63
|
end
|
@@ -18,6 +18,10 @@ module MetadataPresenter
|
|
18
18
|
to_h.reject { |k, _| k.in?(NOT_EDITABLE) }
|
19
19
|
end
|
20
20
|
|
21
|
+
def find_component_by_uuid(uuid)
|
22
|
+
all_components.find { |component| component.uuid == uuid }
|
23
|
+
end
|
24
|
+
|
21
25
|
def all_components
|
22
26
|
[components, extra_components].flatten.compact
|
23
27
|
end
|
@@ -58,6 +62,10 @@ module MetadataPresenter
|
|
58
62
|
components.select(&:upload?)
|
59
63
|
end
|
60
64
|
|
65
|
+
def standalone?
|
66
|
+
type == 'page.standalone'
|
67
|
+
end
|
68
|
+
|
61
69
|
private
|
62
70
|
|
63
71
|
def to_components(node_components, collection:)
|
@@ -27,6 +27,8 @@ module MetadataPresenter
|
|
27
27
|
date_answer(component.id)
|
28
28
|
elsif component && component.type == 'upload'
|
29
29
|
upload_answer(component.id)
|
30
|
+
elsif component && component.type == 'checkboxes'
|
31
|
+
answers[method_name.to_s].to_a
|
30
32
|
else
|
31
33
|
answers[method_name.to_s]
|
32
34
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class PreviousPage
|
3
|
+
include ActiveModel::Model
|
4
|
+
attr_accessor :service, :user_data, :current_page, :referrer
|
5
|
+
|
6
|
+
def page
|
7
|
+
# what happens when a user enters in the middle of the flow
|
8
|
+
return if no_current_or_referrer_pages? || service.no_back_link?(current_page)
|
9
|
+
|
10
|
+
if flow.present?
|
11
|
+
return referrer_page if return_to_referrer?
|
12
|
+
|
13
|
+
TraversedPages.new(service, user_data, current_page).last
|
14
|
+
else
|
15
|
+
service.previous_page(current_page: current_page, referrer: referrer)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def flow
|
20
|
+
service.metadata['flow']
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def referrer_page
|
26
|
+
@referrer_page ||= service.find_page_by_url(URI(referrer).path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def return_to_referrer?
|
30
|
+
current_page.standalone? ||
|
31
|
+
(referrer_page && referrer_page.standalone?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def no_current_or_referrer_pages?
|
35
|
+
current_page.blank? || referrer.nil?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -5,6 +5,12 @@ class MetadataPresenter::Service < MetadataPresenter::Metadata
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
def flow(page_uuid)
|
9
|
+
MetadataPresenter::Flow.new(metadata.flow[page_uuid])
|
10
|
+
rescue StandardError
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
8
14
|
def standalone_pages
|
9
15
|
@standalone_pages ||= metadata.standalone_pages.map do |page|
|
10
16
|
MetadataPresenter::Page.new(page, editor: editor?)
|
@@ -33,6 +39,8 @@ class MetadataPresenter::Service < MetadataPresenter::Metadata
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def previous_page(current_page:, referrer:)
|
42
|
+
return if current_page.nil? || referrer.nil?
|
43
|
+
|
36
44
|
unless no_back_link?(current_page)
|
37
45
|
flow_page(current_page) || referrer_page(referrer)
|
38
46
|
end
|
@@ -48,16 +56,16 @@ class MetadataPresenter::Service < MetadataPresenter::Metadata
|
|
48
56
|
MetadataPresenter::Meta.new(configuration['meta'])
|
49
57
|
end
|
50
58
|
|
59
|
+
def no_back_link?(current_page)
|
60
|
+
current_page == start_page || current_page == confirmation_page
|
61
|
+
end
|
62
|
+
|
51
63
|
private
|
52
64
|
|
53
65
|
def all_pages
|
54
66
|
@all_pages ||= pages + standalone_pages
|
55
67
|
end
|
56
68
|
|
57
|
-
def no_back_link?(current_page)
|
58
|
-
current_page == start_page || current_page == confirmation_page
|
59
|
-
end
|
60
|
-
|
61
69
|
def flow_page(current_page)
|
62
70
|
page_index = pages.index(current_page)
|
63
71
|
pages[page_index - 1] if page_index.present?
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class TraversedPages
|
3
|
+
attr_reader :service, :user_data, :current_page
|
4
|
+
|
5
|
+
def initialize(service, user_data, current_page)
|
6
|
+
@service = service
|
7
|
+
@user_data = user_data
|
8
|
+
@pages = [service.start_page]
|
9
|
+
@current_page = current_page
|
10
|
+
end
|
11
|
+
|
12
|
+
delegate :last, to: :all
|
13
|
+
|
14
|
+
def all
|
15
|
+
page_uuid = service.start_page.uuid
|
16
|
+
|
17
|
+
service.metadata['flow'].size.times do
|
18
|
+
break if page_uuid == current_page.uuid
|
19
|
+
|
20
|
+
flow_object = service.flow(page_uuid)
|
21
|
+
|
22
|
+
if flow_object.branch?
|
23
|
+
page = EvaluateConditions.new(
|
24
|
+
service: service,
|
25
|
+
flow: flow_object,
|
26
|
+
user_data: user_data
|
27
|
+
).page
|
28
|
+
page_uuid = page.uuid
|
29
|
+
else
|
30
|
+
page_uuid = flow_object.default_next
|
31
|
+
page = service.find_page_by_uuid(page_uuid)
|
32
|
+
end
|
33
|
+
|
34
|
+
@pages.push(page) if page && page.uuid != current_page.uuid
|
35
|
+
end
|
36
|
+
|
37
|
+
@pages
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class BaseOperator
|
3
|
+
attr_reader :actual, :expected
|
4
|
+
|
5
|
+
def initialize(actual, expected)
|
6
|
+
@actual = actual
|
7
|
+
@expected = expected
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate?
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Method signature for collection components (a.k.a checkboxes)
|
15
|
+
#
|
16
|
+
def evaluate_collection?
|
17
|
+
evaluate?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|