forest_liana 6.0.0.pre.beta.2 → 6.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +105 -0
- data/app/controllers/forest_liana/authentication_controller.rb +5 -5
- data/app/controllers/forest_liana/resources_controller.rb +14 -17
- data/app/controllers/forest_liana/smart_actions_controller.rb +10 -5
- data/app/helpers/forest_liana/is_same_data_structure_helper.rb +44 -0
- data/app/helpers/forest_liana/widgets_helper.rb +59 -0
- data/app/models/forest_liana/model/action.rb +2 -1
- data/app/serializers/forest_liana/stripe_invoice_serializer.rb +5 -5
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/authentication.rb +0 -2
- data/app/services/forest_liana/authorization_getter.rb +23 -21
- data/app/services/forest_liana/oidc_client_manager.rb +9 -5
- data/app/services/forest_liana/permissions_checker.rb +117 -56
- data/app/services/forest_liana/permissions_formatter.rb +52 -0
- data/app/services/forest_liana/permissions_getter.rb +52 -17
- data/app/services/forest_liana/resource_creator.rb +1 -1
- data/app/services/forest_liana/resource_updater.rb +3 -3
- data/app/services/forest_liana/resources_getter.rb +3 -3
- data/app/services/forest_liana/schema_utils.rb +8 -3
- data/app/services/forest_liana/scope_validator.rb +8 -7
- data/app/services/forest_liana/stripe_invoice_getter.rb +1 -1
- data/app/services/forest_liana/stripe_invoices_getter.rb +1 -1
- data/app/services/forest_liana/stripe_source_getter.rb +1 -1
- data/app/services/forest_liana/stripe_sources_getter.rb +1 -1
- data/app/services/forest_liana/utils/beta_schema_utils.rb +13 -0
- data/config/initializers/error-messages.rb +3 -0
- data/config/initializers/errors.rb +21 -2
- data/config/routes.rb +2 -4
- data/lib/forest_liana.rb +1 -0
- data/lib/forest_liana/bootstrapper.rb +31 -5
- data/lib/forest_liana/schema_file_updater.rb +1 -0
- data/lib/forest_liana/version.rb +1 -1
- data/lib/generators/forest_liana/install_generator.rb +13 -5
- data/spec/dummy/app/assets/config/manifest.js +1 -0
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/db/migrate/20190226172951_create_user.rb +1 -1
- data/spec/dummy/db/migrate/20190226173051_create_isle.rb +1 -1
- data/spec/dummy/db/migrate/20190226174951_create_tree.rb +1 -1
- data/spec/dummy/db/migrate/20190716130830_add_age_to_tree.rb +1 -1
- data/spec/dummy/db/migrate/20190716135241_add_type_to_user.rb +1 -1
- data/spec/dummy/db/schema.rb +18 -20
- data/spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb +87 -0
- data/spec/requests/actions_controller_spec.rb +222 -0
- data/spec/requests/authentications_spec.rb +12 -13
- data/spec/requests/resources_spec.rb +4 -4
- data/spec/services/forest_liana/apimap_sorter_spec.rb +6 -4
- data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +711 -0
- data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +831 -0
- data/spec/services/forest_liana/permissions_formatter_spec.rb +222 -0
- data/spec/services/forest_liana/permissions_getter_spec.rb +83 -0
- data/spec/spec_helper.rb +3 -0
- data/test/dummy/app/assets/config/manifest.js +1 -0
- data/test/dummy/config/application.rb +1 -1
- data/test/dummy/db/migrate/20150608130516_create_date_field.rb +1 -1
- data/test/dummy/db/migrate/20150608131430_create_integer_field.rb +1 -1
- data/test/dummy/db/migrate/20150608131603_create_decimal_field.rb +1 -1
- data/test/dummy/db/migrate/20150608131610_create_float_field.rb +1 -1
- data/test/dummy/db/migrate/20150608132159_create_boolean_field.rb +1 -1
- data/test/dummy/db/migrate/20150608132621_create_string_field.rb +1 -1
- data/test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb +1 -1
- data/test/dummy/db/migrate/20150608133044_create_has_one_field.rb +1 -1
- data/test/dummy/db/migrate/20150608150016_create_has_many_field.rb +1 -1
- data/test/dummy/db/migrate/20150609114636_create_belongs_to_class_name_field.rb +1 -1
- data/test/dummy/db/migrate/20150612112520_create_has_and_belongs_to_many_field.rb +1 -1
- data/test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb +1 -1
- data/test/dummy/db/migrate/20150623115554_create_has_many_class_name_field.rb +1 -1
- data/test/dummy/db/migrate/20150814081918_create_has_many_through_field.rb +1 -1
- data/test/dummy/db/migrate/20160627172810_create_owner.rb +1 -1
- data/test/dummy/db/migrate/20160627172951_create_tree.rb +1 -1
- data/test/dummy/db/migrate/20160628173505_add_timestamps.rb +1 -1
- data/test/dummy/db/migrate/20170614141921_create_serialize_field.rb +1 -1
- data/test/dummy/db/migrate/20181111162121_create_references_table.rb +1 -1
- data/test/routing/route_test.rb +0 -12
- data/test/services/forest_liana/resources_getter_test.rb +1 -1
- metadata +132 -147
- data/app/controllers/forest_liana/sessions_controller.rb +0 -95
- data/app/serializers/forest_liana/session_serializer.rb +0 -33
- data/app/services/forest_liana/login_handler.rb +0 -99
- data/app/services/forest_liana/two_factor_registration_confirmer.rb +0 -36
- data/app/services/forest_liana/user_secret_creator.rb +0 -26
- data/spec/requests/sessions_spec.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a5fa2377990f8fa7bbbf8267b3250a6b5f29f44e1b9f37d82f152281851875e
|
4
|
+
data.tar.gz: 9115346647db03749473cf9b7ed6b9fa9c7afa0a678551db264cae781533311c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14a06f171447f52515131ecfbfe308caacea813dad47d67eee45af086b134ac73677580a0e1f5a65bbbfdde1d078410d8cf3e7adb48ed588aab5049ef4fa3e50
|
7
|
+
data.tar.gz: 93469f1d98a053c685f9fde26d106907d4f89e3244d7f46abc99a2a0265b4bf22f63f5b652736658880968ac9d48ef4f5aae0a90c80b9d5ce2c8c03677ec6153
|
@@ -1,7 +1,112 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class ActionsController < ForestLiana::BaseController
|
3
|
+
|
3
4
|
def values
|
4
5
|
render serializer: nil, json: {}, status: :ok
|
5
6
|
end
|
7
|
+
|
8
|
+
def get_collection(collection_name)
|
9
|
+
ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_action(collection_name)
|
13
|
+
collection = get_collection(collection_name)
|
14
|
+
begin
|
15
|
+
collection.actions.find {|action| ActiveSupport::Inflector.parameterize(action.name) == params[:action_name]}
|
16
|
+
rescue => error
|
17
|
+
FOREST_LOGGER.error "Smart Action get action retrieval error: #{error}"
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_record
|
23
|
+
model = ForestLiana::SchemaUtils.find_model_from_collection_name(params[:collectionName])
|
24
|
+
redord_getter = ForestLiana::ResourceGetter.new(model, {:id => params[:recordIds][0]})
|
25
|
+
redord_getter.perform
|
26
|
+
redord_getter.record
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_smart_action_load_ctx(fields)
|
30
|
+
fields = fields.reduce({}) do |p, c|
|
31
|
+
ForestLiana::WidgetsHelper.set_field_widget(c)
|
32
|
+
p.update(c[:field] => c.merge!(value: nil))
|
33
|
+
end
|
34
|
+
{:record => get_record, :fields => fields}
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_smart_action_change_ctx(fields)
|
38
|
+
fields = fields.reduce({}) do |p, c|
|
39
|
+
field = c.permit!.to_h.symbolize_keys
|
40
|
+
ForestLiana::WidgetsHelper.set_field_widget(field)
|
41
|
+
p.update(c[:field] => field)
|
42
|
+
end
|
43
|
+
{:record => get_record, :fields => fields}
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_result(result, formatted_fields, action)
|
47
|
+
if result.nil? || !result.is_a?(Hash)
|
48
|
+
return render status: 500, json: { error: 'Error in smart action load hook: hook must return an object' }
|
49
|
+
end
|
50
|
+
is_same_data_structure = ForestLiana::IsSameDataStructureHelper::Analyser.new(formatted_fields, result, 1)
|
51
|
+
unless is_same_data_structure.perform
|
52
|
+
return render status: 500, json: { error: 'Error in smart action hook: fields must be unchanged (no addition nor deletion allowed)' }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Apply result on fields (transform the object back to an array), preserve order.
|
56
|
+
fields = action.fields.map do |field|
|
57
|
+
updated_field = result[field[:field]]
|
58
|
+
|
59
|
+
# Reset `value` when not present in `enums` (which means `enums` has changed).
|
60
|
+
if updated_field[:enums].is_a?(Array)
|
61
|
+
# `value` can be an array if the type of fields is `[x]`
|
62
|
+
if updated_field[:type].is_a?(Array) && updated_field[:value].is_a?(Array) && !(updated_field[:value] - updated_field[:enums]).empty?
|
63
|
+
updated_field[:value] = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# `value` can be any other value
|
67
|
+
if !updated_field[:type].is_a?(Array) && !updated_field[:enums].include?(updated_field[:value])
|
68
|
+
updated_field[:value] = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
updated_field
|
73
|
+
end
|
74
|
+
|
75
|
+
render serializer: nil, json: { fields: fields}, status: :ok
|
76
|
+
end
|
77
|
+
|
78
|
+
def load
|
79
|
+
action = get_action(params[:collectionName])
|
80
|
+
|
81
|
+
if !action
|
82
|
+
render status: 500, json: {error: 'Error in smart action load hook: cannot retrieve action from collection'}
|
83
|
+
else
|
84
|
+
# Transform fields from array to an object to ease usage in hook, adds null value.
|
85
|
+
context = get_smart_action_load_ctx(action.fields)
|
86
|
+
formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
|
87
|
+
|
88
|
+
# Call the user-defined load hook.
|
89
|
+
result = action.hooks[:load].(context)
|
90
|
+
|
91
|
+
handle_result(result, formatted_fields, action)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def change
|
96
|
+
action = get_action(params[:collectionName])
|
97
|
+
|
98
|
+
if !action
|
99
|
+
render status: 500, json: {error: 'Error in smart action change hook: cannot retrieve action from collection'}
|
100
|
+
else
|
101
|
+
# Transform fields from array to an object to ease usage in hook.
|
102
|
+
context = get_smart_action_change_ctx(params[:fields])
|
103
|
+
formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
|
104
|
+
|
105
|
+
# Call the user-defined change hook.
|
106
|
+
result = action.hooks[:change][params[:changedField]].(context)
|
107
|
+
|
108
|
+
handle_result(result, formatted_fields, action)
|
109
|
+
end
|
110
|
+
end
|
6
111
|
end
|
7
112
|
end
|
@@ -46,7 +46,7 @@ module ForestLiana
|
|
46
46
|
{ 'renderingId' => rendering_id },
|
47
47
|
)
|
48
48
|
|
49
|
-
|
49
|
+
render json: { authorizationUrl: result['authorization_url']}, status: 200
|
50
50
|
rescue => error
|
51
51
|
render json: { errors: [{ status: 500, detail: error.message }] },
|
52
52
|
status: :internal_server_error, serializer: nil
|
@@ -69,7 +69,7 @@ module ForestLiana
|
|
69
69
|
httponly: true,
|
70
70
|
secure: true,
|
71
71
|
expires: ForestLiana::Token.expiration_in_days,
|
72
|
-
|
72
|
+
same_site: :None,
|
73
73
|
path: '/'
|
74
74
|
},
|
75
75
|
)
|
@@ -86,8 +86,8 @@ module ForestLiana
|
|
86
86
|
render json: response_body, status: 200
|
87
87
|
|
88
88
|
rescue => error
|
89
|
-
render json: { errors: [{ status: 500, detail: error.message }] },
|
90
|
-
status: :internal_server_error, serializer: nil
|
89
|
+
render json: { errors: [{ status: error.try(:error_code) || 500, detail: error.message }] },
|
90
|
+
status: error.status || :internal_server_error, serializer: nil
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -104,7 +104,7 @@ module ForestLiana
|
|
104
104
|
httponly: true,
|
105
105
|
secure: true,
|
106
106
|
expires: Time.at(0),
|
107
|
-
|
107
|
+
same_site: :None,
|
108
108
|
path: '/'
|
109
109
|
},
|
110
110
|
)
|
@@ -16,18 +16,15 @@ module ForestLiana
|
|
16
16
|
def index
|
17
17
|
begin
|
18
18
|
if request.format == 'csv'
|
19
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
20
|
-
return head :forbidden unless checker.is_authorized?
|
21
|
-
elsif params.has_key?(:searchToEdit)
|
22
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'searchToEdit', @rendering_id)
|
19
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'exportEnabled', @rendering_id, user_id: forest_user['id'])
|
23
20
|
return head :forbidden unless checker.is_authorized?
|
24
21
|
else
|
25
22
|
checker = ForestLiana::PermissionsChecker.new(
|
26
23
|
@resource,
|
27
|
-
'
|
24
|
+
'browseEnabled',
|
28
25
|
@rendering_id,
|
29
|
-
|
30
|
-
get_collection_list_permission_info(forest_user, request)
|
26
|
+
user_id: forest_user['id'],
|
27
|
+
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
31
28
|
)
|
32
29
|
return head :forbidden unless checker.is_authorized?
|
33
30
|
end
|
@@ -59,10 +56,10 @@ module ForestLiana
|
|
59
56
|
begin
|
60
57
|
checker = ForestLiana::PermissionsChecker.new(
|
61
58
|
@resource,
|
62
|
-
'
|
59
|
+
'browseEnabled',
|
63
60
|
@rendering_id,
|
64
|
-
|
65
|
-
get_collection_list_permission_info(forest_user, request)
|
61
|
+
user_id: forest_user['id'],
|
62
|
+
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
66
63
|
)
|
67
64
|
return head :forbidden unless checker.is_authorized?
|
68
65
|
|
@@ -89,7 +86,7 @@ module ForestLiana
|
|
89
86
|
|
90
87
|
def show
|
91
88
|
begin
|
92
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
89
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'readEnabled', @rendering_id, user_id: forest_user['id'])
|
93
90
|
return head :forbidden unless checker.is_authorized?
|
94
91
|
|
95
92
|
getter = ForestLiana::ResourceGetter.new(@resource, params)
|
@@ -104,7 +101,7 @@ module ForestLiana
|
|
104
101
|
|
105
102
|
def create
|
106
103
|
begin
|
107
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
104
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'addEnabled', @rendering_id, user_id: forest_user['id'])
|
108
105
|
return head :forbidden unless checker.is_authorized?
|
109
106
|
|
110
107
|
creator = ForestLiana::ResourceCreator.new(@resource, params)
|
@@ -127,7 +124,7 @@ module ForestLiana
|
|
127
124
|
|
128
125
|
def update
|
129
126
|
begin
|
130
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
127
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'editEnabled', @rendering_id, user_id: forest_user['id'])
|
131
128
|
return head :forbidden unless checker.is_authorized?
|
132
129
|
|
133
130
|
updater = ForestLiana::ResourceUpdater.new(@resource, params)
|
@@ -149,7 +146,7 @@ module ForestLiana
|
|
149
146
|
end
|
150
147
|
|
151
148
|
def destroy
|
152
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
149
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'deleteEnabled', @rendering_id, user_id: forest_user['id'])
|
153
150
|
return head :forbidden unless checker.is_authorized?
|
154
151
|
|
155
152
|
@resource.destroy(params[:id]) if @resource.exists?(params[:id])
|
@@ -161,7 +158,7 @@ module ForestLiana
|
|
161
158
|
end
|
162
159
|
|
163
160
|
def destroy_bulk
|
164
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
161
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'deleteEnabled', @rendering_id, user_id: forest_user['id'])
|
165
162
|
return head :forbidden unless checker.is_authorized?
|
166
163
|
|
167
164
|
ids = ForestLiana::ResourcesGetter.get_ids_from_request(params)
|
@@ -245,8 +242,8 @@ module ForestLiana
|
|
245
242
|
@collection ||= ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
|
246
243
|
end
|
247
244
|
|
248
|
-
# NOTICE: Return a formatted object containing the request condition filters and
|
249
|
-
# the user id used by the scope validator class to validate if scope is
|
245
|
+
# NOTICE: Return a formatted object containing the request condition filters and
|
246
|
+
# the user id used by the scope validator class to validate if scope is
|
250
247
|
# in request
|
251
248
|
def get_collection_list_permission_info(user, collection_list_request)
|
252
249
|
{
|
@@ -19,14 +19,15 @@ module ForestLiana
|
|
19
19
|
|
20
20
|
def check_permission_for_smart_route
|
21
21
|
begin
|
22
|
-
|
22
|
+
|
23
23
|
smart_action_request = get_smart_action_request
|
24
24
|
if !smart_action_request.nil? && smart_action_request.has_key?(:smart_action_id)
|
25
25
|
checker = ForestLiana::PermissionsChecker.new(
|
26
26
|
find_resource(smart_action_request[:collection_name]),
|
27
27
|
'actions',
|
28
28
|
@rendering_id,
|
29
|
-
|
29
|
+
user_id: forest_user['id'],
|
30
|
+
smart_action_request_info: get_smart_action_request_info
|
30
31
|
)
|
31
32
|
return head :forbidden unless checker.is_authorized?
|
32
33
|
else
|
@@ -54,10 +55,14 @@ module ForestLiana
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
# smart action permissions are retrieved from the action's endpoint and http_method
|
59
|
+
def get_smart_action_request_info
|
60
|
+
endpoint = request.fullpath
|
61
|
+
# Trim starting '/'
|
62
|
+
endpoint[0] = '' if endpoint[0] == '/'
|
58
63
|
{
|
59
|
-
|
60
|
-
|
64
|
+
endpoint: endpoint,
|
65
|
+
http_method: request.request_method
|
61
66
|
}
|
62
67
|
end
|
63
68
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ForestLiana
|
4
|
+
module IsSameDataStructureHelper
|
5
|
+
class Analyser
|
6
|
+
def initialize(object, other, deep = 0)
|
7
|
+
@object = object
|
8
|
+
@other = other
|
9
|
+
@deep = deep
|
10
|
+
end
|
11
|
+
|
12
|
+
def are_objects(object, other)
|
13
|
+
object && other && object.is_a?(Hash) && other.is_a?(Hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_keys(object, other, step = 0)
|
17
|
+
unless are_objects(object, other)
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
object_keys = object.keys
|
22
|
+
other_keys = other.keys
|
23
|
+
|
24
|
+
if object_keys.length != other_keys.length
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
object_keys_set = object_keys.to_set
|
29
|
+
other_keys.each { |key|
|
30
|
+
if !object_keys_set.member?(key) || (step + 1 <= @deep && !check_keys(object[key], other[key], step + 1))
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
return true
|
36
|
+
end
|
37
|
+
|
38
|
+
def perform
|
39
|
+
check_keys(@object, @other)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ForestLiana
|
4
|
+
module WidgetsHelper
|
5
|
+
|
6
|
+
@widget_edit_list = [
|
7
|
+
'address editor',
|
8
|
+
'belongsto typeahead',
|
9
|
+
'belongsto dropdown',
|
10
|
+
'boolean editor',
|
11
|
+
'checkboxes',
|
12
|
+
'color editor',
|
13
|
+
'date editor',
|
14
|
+
'dropdown',
|
15
|
+
'embedded document editor',
|
16
|
+
'file picker',
|
17
|
+
'json code editor',
|
18
|
+
'input array',
|
19
|
+
'multiple select',
|
20
|
+
'number input',
|
21
|
+
'point editor',
|
22
|
+
'price editor',
|
23
|
+
'radio button',
|
24
|
+
'rich text',
|
25
|
+
'text area editor',
|
26
|
+
'text editor',
|
27
|
+
'time input',
|
28
|
+
]
|
29
|
+
|
30
|
+
@v1_to_v2_edit_widgets_mapping = {
|
31
|
+
address: 'address editor',
|
32
|
+
'belongsto select': 'belongsto dropdown',
|
33
|
+
'color picker': 'color editor',
|
34
|
+
'date picker': 'date editor',
|
35
|
+
price: 'price editor',
|
36
|
+
'JSON editor': 'json code editor',
|
37
|
+
'rich text editor': 'rich text',
|
38
|
+
'text area': 'text area editor',
|
39
|
+
'text input': 'text editor',
|
40
|
+
}
|
41
|
+
|
42
|
+
def self.set_field_widget(field)
|
43
|
+
|
44
|
+
if field[:widget]
|
45
|
+
if @v1_to_v2_edit_widgets_mapping[field[:widget].to_sym]
|
46
|
+
field[:widgetEdit] = {name: @v1_to_v2_edit_widgets_mapping[field[:widget].to_sym], parameters: {}}
|
47
|
+
elsif @widget_edit_list.include?(field[:widget])
|
48
|
+
field[:widgetEdit] = {name: field[:widget], parameters: {}}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if !field.key?(:widgetEdit)
|
53
|
+
field[:widgetEdit] = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
field.delete(:widget)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -5,7 +5,7 @@ class ForestLiana::Model::Action
|
|
5
5
|
extend ActiveModel::Naming
|
6
6
|
|
7
7
|
attr_accessor :id, :name, :base_url, :endpoint, :http_method, :fields, :redirect,
|
8
|
-
:type, :download
|
8
|
+
:type, :download, :hooks
|
9
9
|
|
10
10
|
def initialize(attributes = {})
|
11
11
|
if attributes.key?(:global)
|
@@ -66,6 +66,7 @@ class ForestLiana::Model::Action
|
|
66
66
|
@base_url ||= nil
|
67
67
|
@type ||= "bulk"
|
68
68
|
@download ||= false
|
69
|
+
@hooks = !@hooks.nil? ? @hooks.symbolize_keys : nil
|
69
70
|
end
|
70
71
|
|
71
72
|
def persisted?
|
@@ -3,20 +3,20 @@ module ForestLiana
|
|
3
3
|
include JSONAPI::Serializer
|
4
4
|
|
5
5
|
attribute :amount_due
|
6
|
+
attribute :amount_paid
|
7
|
+
attribute :amount_remaining
|
8
|
+
attribute :application_fee_amount
|
6
9
|
attribute :attempt_count
|
7
10
|
attribute :attempted
|
8
|
-
attribute :closed
|
9
11
|
attribute :currency
|
10
|
-
attribute :
|
11
|
-
attribute :forgiven
|
12
|
+
attribute :due_date
|
12
13
|
attribute :paid
|
13
14
|
attribute :period_end
|
14
15
|
attribute :period_start
|
16
|
+
attribute :status
|
15
17
|
attribute :subtotal
|
16
18
|
attribute :total
|
17
|
-
attribute :application_fee
|
18
19
|
attribute :tax
|
19
|
-
attribute :tax_percent
|
20
20
|
|
21
21
|
has_one :customer
|
22
22
|
|