api_maker 0.0.1 → 0.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/api_maker/api_helpers/api_maker_helpers.rb +5 -0
- data/app/api_maker/services/can_can/load_abilities.rb +30 -0
- data/app/api_maker/services/devise/sign_in.rb +64 -0
- data/app/api_maker/services/devise/sign_out.rb +9 -0
- data/app/api_maker/services/models/find_or_create_by.rb +18 -0
- data/app/channels/api_maker/subscriptions_channel.rb +33 -2
- data/app/controllers/api_maker/base_controller.rb +7 -3
- data/app/controllers/api_maker/commands_controller.rb +26 -4
- data/app/controllers/api_maker/session_statuses_controller.rb +1 -1
- data/app/services/api_maker/abilities_loader.rb +104 -0
- data/app/services/api_maker/application_service.rb +2 -1
- data/app/services/api_maker/base_command.rb +248 -0
- data/app/services/api_maker/collection_command_service.rb +29 -15
- data/app/services/api_maker/collection_loader.rb +124 -0
- data/app/services/api_maker/command_failed_error.rb +3 -0
- data/app/services/api_maker/command_response.rb +17 -6
- data/app/services/api_maker/command_service.rb +3 -3
- data/app/services/api_maker/create_command.rb +11 -26
- data/app/services/api_maker/create_command_service.rb +3 -3
- data/app/services/api_maker/database_type.rb +9 -0
- data/app/services/api_maker/deep_merge_params.rb +26 -0
- data/app/services/api_maker/deserializer.rb +35 -0
- data/app/services/api_maker/destroy_command.rb +15 -21
- data/app/services/api_maker/destroy_command_service.rb +3 -3
- data/app/services/api_maker/generate_react_native_api_service.rb +3 -19
- data/app/services/api_maker/include_helpers.rb +17 -0
- data/app/services/api_maker/index_command.rb +8 -88
- data/app/services/api_maker/index_command_service.rb +5 -5
- data/app/services/api_maker/js_method_namer_service.rb +1 -1
- data/app/services/api_maker/locals_from_controller.rb +14 -0
- data/app/services/api_maker/member_command_service.rb +15 -13
- data/app/services/api_maker/model_classes_java_script_generator_service.rb +37 -0
- data/app/services/api_maker/model_content_generator_service.rb +17 -21
- data/app/services/api_maker/models/save.rb +29 -0
- data/app/services/api_maker/models_finder_service.rb +6 -2
- data/app/services/api_maker/models_generator_service.rb +6 -43
- data/app/services/api_maker/move_components_to_routes.rb +50 -0
- data/app/services/api_maker/primary_id_for_model.rb +6 -0
- data/app/services/api_maker/reset_indexed_db_service.rb +36 -0
- data/app/services/api_maker/routes_file_reloader.rb +20 -0
- data/app/services/api_maker/select_columns_on_collection.rb +78 -0
- data/app/services/api_maker/select_parser.rb +32 -0
- data/app/services/api_maker/service_command.rb +27 -0
- data/app/services/api_maker/service_command_service.rb +14 -0
- data/app/services/api_maker/simple_model_errors.rb +52 -0
- data/app/services/api_maker/update_command.rb +8 -24
- data/app/services/api_maker/update_command_service.rb +3 -3
- data/app/services/api_maker/valid_command.rb +4 -13
- data/app/services/api_maker/valid_command_service.rb +3 -3
- data/app/services/api_maker/validation_errors_generator_service.rb +146 -0
- data/app/views/api_maker/_data.html.erb +17 -11
- data/config/routes.rb +0 -2
- data/lib/api_maker/ability.rb +22 -7
- data/lib/api_maker/ability_loader.rb +9 -6
- data/lib/api_maker/base_collection_instance.rb +15 -0
- data/lib/api_maker/base_resource.rb +135 -9
- data/lib/api_maker/base_service.rb +14 -0
- data/lib/api_maker/collection_serializer.rb +95 -34
- data/lib/api_maker/command_spec_helper.rb +41 -11
- data/lib/api_maker/configuration.rb +31 -4
- data/lib/api_maker/expect_to_able_to_helper.rb +31 -0
- data/lib/api_maker/individual_command.rb +24 -9
- data/lib/api_maker/javascript/model-template.js.erb +39 -25
- data/lib/api_maker/javascript/models.js.erb +6 -0
- data/lib/api_maker/loader.rb +1 -1
- data/lib/api_maker/memory_storage.rb +1 -1
- data/lib/api_maker/model_extensions.rb +34 -18
- data/lib/api_maker/permitted_params_argument.rb +5 -1
- data/lib/api_maker/preloader.rb +71 -32
- data/lib/api_maker/preloader_base.rb +108 -0
- data/lib/api_maker/preloader_belongs_to.rb +34 -33
- data/lib/api_maker/preloader_has_many.rb +45 -39
- data/lib/api_maker/preloader_has_one.rb +30 -47
- data/lib/api_maker/railtie.rb +3 -11
- data/lib/api_maker/relationship_preloader.rb +42 -0
- data/lib/api_maker/resource_routing.rb +18 -4
- data/lib/api_maker/result_parser.rb +34 -20
- data/lib/api_maker/serializer.rb +53 -22
- data/lib/api_maker/spec_helper/browser_logs.rb +14 -0
- data/lib/api_maker/spec_helper/execute_collection_command.rb +46 -0
- data/lib/api_maker/spec_helper/execute_member_command.rb +52 -0
- data/lib/api_maker/spec_helper/expect_no_browser_errors.rb +18 -0
- data/lib/api_maker/spec_helper/wait_for_expect.rb +20 -0
- data/lib/api_maker/spec_helper/wait_for_flash_message.rb +21 -0
- data/lib/api_maker/spec_helper.rb +112 -48
- data/lib/api_maker/version.rb +1 -1
- data/lib/api_maker.rb +7 -3
- metadata +108 -89
- data/README.md +0 -476
- data/app/controllers/api_maker/devise_controller.rb +0 -60
- data/lib/api_maker/base_command.rb +0 -81
- data/lib/api_maker/javascript/api.js +0 -92
- data/lib/api_maker/javascript/base-model.js +0 -543
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +0 -16
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +0 -47
- data/lib/api_maker/javascript/bootstrap/card.jsx +0 -79
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +0 -127
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +0 -105
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +0 -136
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +0 -80
- data/lib/api_maker/javascript/bootstrap/select.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +0 -203
- data/lib/api_maker/javascript/cable-connection-pool.js +0 -169
- data/lib/api_maker/javascript/cable-subscription-pool.js +0 -111
- data/lib/api_maker/javascript/cable-subscription.js +0 -33
- data/lib/api_maker/javascript/collection.js +0 -186
- data/lib/api_maker/javascript/commands-pool.js +0 -123
- data/lib/api_maker/javascript/custom-error.js +0 -14
- data/lib/api_maker/javascript/deserializer.js +0 -35
- data/lib/api_maker/javascript/devise.js.erb +0 -113
- data/lib/api_maker/javascript/error-logger.js +0 -119
- data/lib/api_maker/javascript/event-connection.jsx +0 -24
- data/lib/api_maker/javascript/event-created.jsx +0 -26
- data/lib/api_maker/javascript/event-destroyed.jsx +0 -26
- data/lib/api_maker/javascript/event-emitter-listener.jsx +0 -32
- data/lib/api_maker/javascript/event-listener.jsx +0 -41
- data/lib/api_maker/javascript/event-updated.jsx +0 -26
- data/lib/api_maker/javascript/form-data-to-object.js +0 -70
- data/lib/api_maker/javascript/included.js +0 -39
- data/lib/api_maker/javascript/key-value-store.js +0 -47
- data/lib/api_maker/javascript/logger.js +0 -23
- data/lib/api_maker/javascript/model-name.js +0 -21
- data/lib/api_maker/javascript/models-response-reader.js +0 -43
- data/lib/api_maker/javascript/paginate.jsx +0 -128
- data/lib/api_maker/javascript/params.js +0 -68
- data/lib/api_maker/javascript/resource-route.jsx +0 -75
- data/lib/api_maker/javascript/resource-routes.jsx +0 -36
- data/lib/api_maker/javascript/result.js +0 -25
- data/lib/api_maker/javascript/session-status-updater.js +0 -113
- data/lib/api_maker/javascript/sort-link.jsx +0 -88
- data/lib/api_maker/javascript/updated-attribute.jsx +0 -60
- data/lib/api_maker/preloader_through.rb +0 -101
- data/lib/api_maker/relationship_includer.rb +0 -42
@@ -1,24 +1,38 @@
|
|
1
1
|
class ApiMaker::CollectionCommandService < ApiMaker::CommandService
|
2
|
-
def
|
3
|
-
|
2
|
+
def perform
|
3
|
+
ApiMaker::Configuration.profile(-> { "CollectionCommand: #{namespace}::#{command_name}" }) do
|
4
|
+
if authorized?
|
5
|
+
constant.execute_in_thread!(
|
6
|
+
ability: ability,
|
7
|
+
api_maker_args: api_maker_args,
|
8
|
+
collection: nil,
|
9
|
+
commands: commands,
|
10
|
+
command_response: command_response,
|
11
|
+
controller: controller
|
12
|
+
)
|
13
|
+
else
|
14
|
+
fail_with_no_access
|
15
|
+
end
|
4
16
|
|
5
|
-
|
6
|
-
|
7
|
-
args: args,
|
8
|
-
collection: nil,
|
9
|
-
commands: commands,
|
10
|
-
command_response: command_response,
|
11
|
-
controller: controller
|
12
|
-
)
|
13
|
-
|
14
|
-
ServicePattern::Response.new(success: true)
|
17
|
+
succeed!
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
|
-
def
|
18
|
-
|
21
|
+
def authorized?
|
22
|
+
ability.can?(command_name.to_sym, model_class)
|
19
23
|
end
|
20
24
|
|
21
25
|
def constant
|
22
|
-
@constant ||= "Commands::#{namespace}::#{
|
26
|
+
@constant ||= "Commands::#{namespace}::#{command_name.camelize}".constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def fail_with_no_access
|
30
|
+
commands.each_key do |command_id|
|
31
|
+
command_response.error_for_command(
|
32
|
+
command_id,
|
33
|
+
success: false,
|
34
|
+
errors: ["No access to '#{command_name}' on '#{model_class.name}'"]
|
35
|
+
)
|
36
|
+
end
|
23
37
|
end
|
24
38
|
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
class ApiMaker::CollectionLoader < ApiMaker::ApplicationService
|
2
|
+
attr_reader :ability, :api_maker_args, :collection, :locals, :params
|
3
|
+
|
4
|
+
def initialize(ability:, api_maker_args:, collection:, locals: nil, params: {})
|
5
|
+
@ability = ability
|
6
|
+
@api_maker_args = api_maker_args
|
7
|
+
@collection = collection
|
8
|
+
@locals = locals || api_maker_args&.dig(:locals) || {}
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform
|
13
|
+
set_query
|
14
|
+
|
15
|
+
if params[:count]
|
16
|
+
count = @query.count
|
17
|
+
count = count.length if count.is_a?(Hash)
|
18
|
+
|
19
|
+
succeed!(count: count)
|
20
|
+
else
|
21
|
+
collection = collection_from_query(@query)
|
22
|
+
response = collection.as_json
|
23
|
+
include_pagination_data(response, @query)
|
24
|
+
|
25
|
+
succeed!(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def filter_custom_accessible_by(collection)
|
30
|
+
return collection if params[:accessible_by].blank?
|
31
|
+
|
32
|
+
collection.accessible_by(ability, params[:accessible_by].to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
def collection_from_query(collection)
|
36
|
+
ApiMaker::CollectionSerializer.new(
|
37
|
+
ability: ability,
|
38
|
+
api_maker_args: api_maker_args,
|
39
|
+
collection: collection,
|
40
|
+
locals: locals,
|
41
|
+
query_params: params
|
42
|
+
).result
|
43
|
+
end
|
44
|
+
|
45
|
+
def distinct_query
|
46
|
+
@query = @query.distinct if params[:distinct]
|
47
|
+
end
|
48
|
+
|
49
|
+
def group_query
|
50
|
+
return if params[:group_by].blank?
|
51
|
+
|
52
|
+
params[:group_by].each do |group_by|
|
53
|
+
if group_by.is_a?(Array)
|
54
|
+
raise "Expected table and column but array length was wrong: #{group_by.length}" unless group_by.length == 2
|
55
|
+
|
56
|
+
resource_class = group_by[0]
|
57
|
+
column_name = group_by[1]
|
58
|
+
model_class = resource_class.model_class
|
59
|
+
raise "Not a valid column name: #{column_name}" unless model_class.column_names.include?(column_name)
|
60
|
+
|
61
|
+
arel_column = model_class.arel_table[column_name]
|
62
|
+
else
|
63
|
+
arel_column = collection.klass.arel_table[group_by]
|
64
|
+
raise "Not a valid column name: #{group_by}" unless collection.klass.column_names.include?(group_by)
|
65
|
+
end
|
66
|
+
|
67
|
+
@query = @query.group(arel_column)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def limit_query
|
72
|
+
@query = @query.limit(params[:limit]) if params[:limit].present?
|
73
|
+
end
|
74
|
+
|
75
|
+
def include_pagination_data(response, collection)
|
76
|
+
return if params[:page].blank?
|
77
|
+
|
78
|
+
countable_collection = collection.except(:distinct).except(:group).except(:select).except(:order)
|
79
|
+
|
80
|
+
Rails.logger.debug { "API maker: CollectionLoader total pages for #{model_class.name}" }
|
81
|
+
total_pages = countable_collection.total_pages
|
82
|
+
|
83
|
+
Rails.logger.debug { "API maker: CollectionLoader total count for #{model_class.name}" }
|
84
|
+
total_count = countable_collection.try(:total_count) || countable_collection.total_entries
|
85
|
+
|
86
|
+
response[:meta] = {
|
87
|
+
currentPage: collection.current_page,
|
88
|
+
perPage: collection.try(:per_page) || collection.limit_value,
|
89
|
+
totalCount: total_count,
|
90
|
+
totalPages: total_pages
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def manage_through_relationship
|
95
|
+
return if params[:through].blank?
|
96
|
+
|
97
|
+
through_model_class = params[:through][:model].safe_constantize
|
98
|
+
through_model = through_model_class.accessible_by(ability).find_by(through_model_class.primary_key => params[:through][:id])
|
99
|
+
|
100
|
+
return if through_model.nil?
|
101
|
+
|
102
|
+
association = ActiveRecord::Associations::Association.new(through_model, through_model_class.reflections.fetch(params[:through][:reflection]))
|
103
|
+
|
104
|
+
query_through = association.scope
|
105
|
+
query_through = query_through.accessible_by(ability)
|
106
|
+
|
107
|
+
filter_custom_accessible_by(query_through)
|
108
|
+
end
|
109
|
+
|
110
|
+
def model_class
|
111
|
+
@model_class ||= collection.klass
|
112
|
+
end
|
113
|
+
|
114
|
+
def set_query
|
115
|
+
@query = manage_through_relationship || collection
|
116
|
+
group_query
|
117
|
+
distinct_query
|
118
|
+
@query = @query.ransack(params[:q]).result
|
119
|
+
limit_query
|
120
|
+
@query = @query.page(params[:page]) if params[:page].present?
|
121
|
+
@query = @query.per_page(params[:per]) if params[:per].present?
|
122
|
+
@query = filter_custom_accessible_by(@query)
|
123
|
+
end
|
124
|
+
end
|
@@ -47,21 +47,32 @@ class ApiMaker::CommandResponse
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def spawn_thread
|
50
|
+
def spawn_thread(&blk)
|
51
|
+
parent_thread = Thread.current
|
52
|
+
|
51
53
|
@threads << Thread.new do
|
54
|
+
child_thread = Thread.current
|
55
|
+
|
52
56
|
Rails.application.executor.wrap do
|
53
|
-
|
54
|
-
|
57
|
+
ApiMaker::Configuration.current.on_thread_callbacks&.each do |on_thread_callback|
|
58
|
+
on_thread_callback.call(parent_thread: parent_thread, child_thread: child_thread)
|
55
59
|
end
|
60
|
+
|
61
|
+
I18n.with_locale(locale, &blk)
|
56
62
|
end
|
57
63
|
rescue => e # rubocop:disable Style/RescueStandardError
|
58
64
|
puts e.inspect
|
59
|
-
puts e.backtrace
|
65
|
+
puts Rails.backtrace_cleaner.clean(e.backtrace)
|
60
66
|
|
61
67
|
Rails.logger.error e.message
|
62
|
-
Rails.logger.error e.backtrace.join("\n")
|
68
|
+
Rails.logger.error Rails.backtrace_cleaner.clean(e.backtrace).join("\n")
|
63
69
|
|
64
|
-
ApiMaker::Configuration.current.report_error(
|
70
|
+
ApiMaker::Configuration.current.report_error(
|
71
|
+
command: nil,
|
72
|
+
controller: controller,
|
73
|
+
error: e,
|
74
|
+
response: nil
|
75
|
+
)
|
65
76
|
end
|
66
77
|
end
|
67
78
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class ApiMaker::CommandService < ApiMaker::ApplicationService
|
2
|
-
attr_reader :ability, :
|
2
|
+
attr_reader :ability, :api_maker_args, :commands, :command_name, :command_response, :controller, :resource_name
|
3
3
|
|
4
|
-
def initialize(ability:,
|
4
|
+
def initialize(ability:, api_maker_args:, commands:, command_name:, command_response:, controller:, resource_name:)
|
5
5
|
@ability = ability
|
6
|
-
@
|
6
|
+
@api_maker_args = api_maker_args
|
7
7
|
@command_name = command_name
|
8
8
|
@command_response = command_response
|
9
9
|
@commands = commands
|
@@ -1,38 +1,27 @@
|
|
1
1
|
class ApiMaker::CreateCommand < ApiMaker::BaseCommand
|
2
|
-
attr_reader :
|
2
|
+
attr_reader :model, :serializer
|
3
3
|
|
4
4
|
def execute!
|
5
|
-
|
6
|
-
@command = command
|
5
|
+
ApiMaker::Configuration.profile(-> { "CreateCommand: #{model_class.name}" }) do
|
7
6
|
@model = collection.klass.new
|
8
|
-
@params = command.args || {}
|
9
7
|
@serializer = serialized_resource(model)
|
10
|
-
|
8
|
+
sanitized_parameters = sanitize_parameters
|
9
|
+
@model.assign_attributes(sanitized_parameters)
|
11
10
|
|
12
|
-
if !current_ability.can?(:create,
|
13
|
-
failure_response(["No access to create that resource"])
|
14
|
-
elsif
|
11
|
+
if !current_ability.can?(:create, model)
|
12
|
+
failure_response(errors: ["No access to create that resource"])
|
13
|
+
elsif model.save
|
15
14
|
success_response
|
16
15
|
else
|
17
|
-
|
16
|
+
failure_save_response(model: model, params: sanitized_parameters)
|
18
17
|
end
|
19
18
|
end
|
20
|
-
|
21
|
-
ServicePattern::Response.new(success: true)
|
22
19
|
end
|
23
20
|
|
24
21
|
def api_maker_resource_class
|
25
22
|
@api_maker_resource_class ||= "Resources::#{collection.klass.name}Resource".constantize
|
26
23
|
end
|
27
24
|
|
28
|
-
def failure_response(errors)
|
29
|
-
command.fail(
|
30
|
-
model: serializer.result,
|
31
|
-
success: false,
|
32
|
-
errors: errors
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
25
|
def resource_instance_class_name
|
37
26
|
@resource_instance_class_name ||= self.class.name.split("::").last.gsub(/Controller$/, "").singularize
|
38
27
|
end
|
@@ -46,16 +35,12 @@ class ApiMaker::CreateCommand < ApiMaker::BaseCommand
|
|
46
35
|
end
|
47
36
|
|
48
37
|
def sanitize_parameters
|
49
|
-
serializer.resource_instance.permitted_params(ApiMaker::PermittedParamsArgument.new(command:
|
50
|
-
end
|
51
|
-
|
52
|
-
def serialized_resource(model)
|
53
|
-
ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
|
38
|
+
serializer.resource_instance.permitted_params(ApiMaker::PermittedParamsArgument.new(command: self, model: model))
|
54
39
|
end
|
55
40
|
|
56
41
|
def success_response
|
57
|
-
|
58
|
-
model:
|
42
|
+
succeed!(
|
43
|
+
model: serialized_model(model),
|
59
44
|
success: true
|
60
45
|
)
|
61
46
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
class ApiMaker::CreateCommandService < ApiMaker::CommandService
|
2
|
-
def
|
2
|
+
def perform
|
3
3
|
ApiMaker::CreateCommand.execute_in_thread!(
|
4
4
|
ability: ability,
|
5
|
-
|
5
|
+
api_maker_args: api_maker_args,
|
6
6
|
collection: collection,
|
7
7
|
commands: commands,
|
8
8
|
command_response: command_response,
|
9
9
|
controller: controller
|
10
10
|
)
|
11
11
|
|
12
|
-
|
12
|
+
succeed!
|
13
13
|
end
|
14
14
|
|
15
15
|
def collection
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class ApiMaker::DeepMergeParams < ApiMaker::ApplicationService
|
2
|
+
attr_reader :hash1, :hash2
|
3
|
+
|
4
|
+
def initialize(hash1, hash2)
|
5
|
+
@hash1 = hash1
|
6
|
+
@hash2 = hash2
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
merged_hash = hash1.deep_merge(hash2) do |_key, this_val, other_val|
|
11
|
+
if this_val.is_a?(Array) && other_val.is_a?(Array) && this_val.length == other_val.length
|
12
|
+
this_val.zip(other_val).collect do |a, b|
|
13
|
+
if a.is_a?(Hash) && b.is_a?(Hash)
|
14
|
+
a.deep_merge(b)
|
15
|
+
else
|
16
|
+
other_val
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
other_val
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
succeed! merged_hash
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class ApiMaker::Deserializer < ApiMaker::ApplicationService
|
2
|
+
attr_reader :arg
|
3
|
+
|
4
|
+
def initialize(arg:)
|
5
|
+
@arg = arg
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
succeed! deserialize
|
10
|
+
end
|
11
|
+
|
12
|
+
def deserialize
|
13
|
+
if arg.is_a?(Array)
|
14
|
+
arg.map { |value| ApiMaker::Deserializer.execute!(arg: value) }
|
15
|
+
elsif arg.is_a?(Hash) || arg.is_a?(ActionController::Parameters)
|
16
|
+
if arg["api_maker_type"] == "resource"
|
17
|
+
"Resources::#{arg.fetch("name")}Resource".safe_constantize
|
18
|
+
elsif arg["api_maker_type"] == "datetime"
|
19
|
+
Time.zone.parse(arg.fetch("value"))
|
20
|
+
else
|
21
|
+
new_hash = arg.class.new
|
22
|
+
arg.each do |key, value|
|
23
|
+
deserialized_key = ApiMaker::Deserializer.execute!(arg: key)
|
24
|
+
deserialized_value = ApiMaker::Deserializer.execute!(arg: value)
|
25
|
+
|
26
|
+
new_hash[deserialized_key] = deserialized_value
|
27
|
+
end
|
28
|
+
|
29
|
+
new_hash
|
30
|
+
end
|
31
|
+
else
|
32
|
+
arg
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,38 +1,32 @@
|
|
1
1
|
class ApiMaker::DestroyCommand < ApiMaker::BaseCommand
|
2
|
-
attr_reader :
|
2
|
+
attr_reader :serializer
|
3
3
|
|
4
4
|
def execute!
|
5
|
-
|
6
|
-
@command = command
|
7
|
-
@model = command.model
|
8
|
-
@params = command.args || {}
|
9
|
-
@serializer = serialized_resource(model)
|
5
|
+
@serializer = serialized_resource(model)
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
7
|
+
if command.model.destroy
|
8
|
+
success_response
|
9
|
+
else
|
10
|
+
failure_response
|
16
11
|
end
|
12
|
+
end
|
17
13
|
|
18
|
-
|
14
|
+
def errors_for_model
|
15
|
+
ActiveRecordBetterDependentErrorMessages::DestroyValidator.(model: model) if model.errors.full_messages.empty?
|
16
|
+
model.errors.full_messages
|
19
17
|
end
|
20
18
|
|
21
19
|
def failure_response
|
22
|
-
|
23
|
-
model:
|
20
|
+
fail!(
|
21
|
+
model: serialized_model(model),
|
24
22
|
success: false,
|
25
|
-
errors:
|
23
|
+
errors: errors_for_model
|
26
24
|
)
|
27
25
|
end
|
28
26
|
|
29
|
-
def serialized_resource(model)
|
30
|
-
ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
|
31
|
-
end
|
32
|
-
|
33
27
|
def success_response
|
34
|
-
|
35
|
-
model:
|
28
|
+
succeed!(
|
29
|
+
model: serialized_model(model),
|
36
30
|
success: true
|
37
31
|
)
|
38
32
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
class ApiMaker::DestroyCommandService < ApiMaker::CommandService
|
2
|
-
def
|
2
|
+
def perform
|
3
3
|
ApiMaker::DestroyCommand.execute_in_thread!(
|
4
4
|
ability: ability,
|
5
|
-
|
5
|
+
api_maker_args: api_maker_args,
|
6
6
|
collection: collection,
|
7
7
|
commands: commands,
|
8
8
|
command_response: command_response,
|
9
9
|
controller: controller
|
10
10
|
)
|
11
11
|
|
12
|
-
|
12
|
+
succeed!
|
13
13
|
end
|
14
14
|
|
15
15
|
def collection
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
|
2
|
-
def
|
2
|
+
def perform
|
3
3
|
check_if_root_folder_defined
|
4
4
|
create_root_folder
|
5
5
|
create_model_files
|
6
6
|
|
7
|
-
|
7
|
+
succeed!
|
8
8
|
end
|
9
9
|
|
10
10
|
def root_folder
|
@@ -21,20 +21,6 @@ class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
|
|
21
21
|
Dir.mkdir(root_folder) unless Dir.exist?(root_folder)
|
22
22
|
end
|
23
23
|
|
24
|
-
def create_model_files
|
25
|
-
model_generator_service.models.each do |model|
|
26
|
-
next if model_generator_service.ignore_model?(model)
|
27
|
-
|
28
|
-
model_content_response = ApiMaker::ModelContentGeneratorService.execute!(model: model)
|
29
|
-
|
30
|
-
if model_content_response.success?
|
31
|
-
File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
|
32
|
-
else
|
33
|
-
puts model_content_response.errors.join(". ")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
24
|
def model_generator_service
|
39
25
|
@model_generator_service ||= ApiMaker::ModelsGeneratorService.new
|
40
26
|
end
|
@@ -50,9 +36,7 @@ class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
|
|
50
36
|
|
51
37
|
def copy_base_model
|
52
38
|
files = %w[
|
53
|
-
|
54
|
-
collection.js commands-pool.js devise.js event-listener.jsx error-logger.js form-data-to-object.js logger.js
|
55
|
-
model-name.js models-response-reader.js result.js event-connection.jsx
|
39
|
+
devise.js event-connection.jsx
|
56
40
|
]
|
57
41
|
path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
|
58
42
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "../../api_maker/api_helpers/api_maker_helpers" # Sometimes this file isn't auto-loaded so it needs to be manually required
|
2
|
+
|
3
|
+
class ApiMaker::IncludeHelpers < ApiMaker::ApplicationService
|
4
|
+
attr_reader :klass
|
5
|
+
|
6
|
+
def initialize(klass:)
|
7
|
+
@klass = klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform
|
11
|
+
::ApiHelpers.constants(false).each do |constant|
|
12
|
+
klass.include ApiHelpers.const_get(constant)
|
13
|
+
end
|
14
|
+
|
15
|
+
succeed!
|
16
|
+
end
|
17
|
+
end
|
@@ -1,96 +1,16 @@
|
|
1
1
|
class ApiMaker::IndexCommand < ApiMaker::BaseCommand
|
2
|
-
attr_reader :params
|
3
|
-
|
4
2
|
def execute!
|
5
|
-
ApiMaker::Configuration.profile("IndexCommand
|
6
|
-
|
7
|
-
@params = command.args || {}
|
8
|
-
|
9
|
-
set_collection
|
10
|
-
|
11
|
-
if params[:count]
|
12
|
-
count = @query.count
|
13
|
-
count = count.length if count.is_a?(Hash)
|
14
|
-
|
15
|
-
command.result(count: count)
|
16
|
-
else
|
17
|
-
collection = collection_from_query(@query.fix)
|
18
|
-
response = collection.as_json
|
19
|
-
include_pagination_data(response, @query)
|
20
|
-
|
21
|
-
command.result(response)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
ServicePattern::Response.new(success: true)
|
27
|
-
end
|
28
|
-
|
29
|
-
def filter_custom_accessible_by(collection)
|
30
|
-
return collection if params[:accessible_by].blank?
|
31
|
-
|
32
|
-
collection.accessible_by(current_ability, params[:accessible_by].to_sym)
|
33
|
-
end
|
3
|
+
ApiMaker::Configuration.profile(-> { "IndexCommand: #{model_class.name}" }) do
|
4
|
+
Rails.logger.debug { "API maker: IndexCommand execute: #{model_class.name} with Ransack: #{command.args&.dig(:q)&.permit!&.to_h}" }
|
34
5
|
|
35
|
-
|
36
|
-
ApiMaker::Configuration.profile("IndexCommand collection_from_query") do
|
37
|
-
select = parse_select(params[:select]&.permit!&.to_hash) if params[:select]
|
38
|
-
|
39
|
-
ApiMaker::CollectionSerializer.new(
|
6
|
+
result = ApiMaker::CollectionLoader.execute!(
|
40
7
|
ability: current_ability,
|
41
|
-
|
8
|
+
api_maker_args: api_maker_args,
|
42
9
|
collection: collection,
|
43
|
-
|
44
|
-
|
45
|
-
)
|
10
|
+
locals: locals,
|
11
|
+
params: command.args || {}
|
12
|
+
)
|
13
|
+
succeed!(result)
|
46
14
|
end
|
47
15
|
end
|
48
|
-
|
49
|
-
def include_pagination_data(response, collection)
|
50
|
-
return if params[:page].blank?
|
51
|
-
|
52
|
-
response[:meta] = {
|
53
|
-
currentPage: collection.current_page,
|
54
|
-
totalCount: collection.try(:total_count) || collection.try(:total_entries),
|
55
|
-
totalPages: collection.total_pages
|
56
|
-
}
|
57
|
-
end
|
58
|
-
|
59
|
-
def manage_through_relationship
|
60
|
-
return if params[:through].blank?
|
61
|
-
|
62
|
-
model_class = params[:through][:model].safe_constantize
|
63
|
-
through_model = model_class.accessible_by(current_ability).find(params[:through][:id])
|
64
|
-
association = ActiveRecord::Associations::Association.new(through_model, model_class.reflections.fetch(params[:through][:reflection]))
|
65
|
-
|
66
|
-
query_through = association.scope
|
67
|
-
query_through = query_through.accessible_by(current_ability)
|
68
|
-
query_through = filter_custom_accessible_by(query_through)
|
69
|
-
query_through
|
70
|
-
end
|
71
|
-
|
72
|
-
# This converts the list of attributes to a hash that contains the data needed for the serializer (so the serializer doesn't have to do it for each model)
|
73
|
-
def parse_select(select)
|
74
|
-
new_select = {}
|
75
|
-
|
76
|
-
select.each do |model_collection_name, attributes|
|
77
|
-
model_class = model_collection_name.underscore.singularize.camelize
|
78
|
-
resource = "Resources::#{model_class}Resource".safe_constantize
|
79
|
-
raise "Resource not found for: #{model_collection_name}" unless resource
|
80
|
-
|
81
|
-
new_attributes = resource._attributes.select { |key| attributes.include?(key.to_s) }
|
82
|
-
new_select[resource.model_class] = new_attributes
|
83
|
-
end
|
84
|
-
|
85
|
-
new_select
|
86
|
-
end
|
87
|
-
|
88
|
-
def set_collection
|
89
|
-
@query = manage_through_relationship || collection
|
90
|
-
@query = @query.distinct if params[:distinct]
|
91
|
-
@query = @query.ransack(params[:q]).result
|
92
|
-
@query = @query.limit(params[:limit]) if params[:limit].present?
|
93
|
-
@query = @query.page(params[:page]) if params[:page].present?
|
94
|
-
@query = filter_custom_accessible_by(@query)
|
95
|
-
end
|
96
16
|
end
|
@@ -1,22 +1,22 @@
|
|
1
1
|
class ApiMaker::IndexCommandService < ApiMaker::CommandService
|
2
|
-
def
|
2
|
+
def perform
|
3
3
|
ApiMaker::IndexCommand.execute_in_thread!(
|
4
4
|
ability: ability,
|
5
|
-
|
5
|
+
api_maker_args: api_maker_args,
|
6
6
|
collection: collection,
|
7
7
|
commands: commands,
|
8
8
|
command_response: command_response,
|
9
9
|
controller: controller
|
10
10
|
)
|
11
11
|
|
12
|
-
|
12
|
+
succeed!
|
13
13
|
end
|
14
14
|
|
15
15
|
def collection
|
16
|
-
@collection ||= model_class.accessible_by(
|
16
|
+
@collection ||= model_class.accessible_by(ability)
|
17
17
|
end
|
18
18
|
|
19
19
|
def ids
|
20
|
-
@ids ||=
|
20
|
+
@ids ||= commands.values.map { |command| command.fetch("primary_key") }
|
21
21
|
end
|
22
22
|
end
|
@@ -3,7 +3,7 @@ class ApiMaker::JsMethodNamerService < ApiMaker::ApplicationService
|
|
3
3
|
@name = name
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
6
|
+
def perform
|
7
7
|
camelized = @name.to_s.camelize
|
8
8
|
new_name = "#{camelized[0..0].downcase}#{camelized[1..camelized.length]}"
|
9
9
|
ServicePattern::Response.new(result: new_name)
|