api_maker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +476 -0
- data/Rakefile +27 -0
- data/app/channels/api_maker/subscriptions_channel.rb +80 -0
- data/app/controllers/api_maker/base_controller.rb +32 -0
- data/app/controllers/api_maker/commands_controller.rb +26 -0
- data/app/controllers/api_maker/devise_controller.rb +60 -0
- data/app/controllers/api_maker/session_statuses_controller.rb +33 -0
- data/app/services/api_maker/application_service.rb +7 -0
- data/app/services/api_maker/collection_command_service.rb +24 -0
- data/app/services/api_maker/command_response.rb +67 -0
- data/app/services/api_maker/command_service.rb +31 -0
- data/app/services/api_maker/create_command.rb +62 -0
- data/app/services/api_maker/create_command_service.rb +18 -0
- data/app/services/api_maker/destroy_command.rb +39 -0
- data/app/services/api_maker/destroy_command_service.rb +22 -0
- data/app/services/api_maker/generate_react_native_api_service.rb +61 -0
- data/app/services/api_maker/index_command.rb +96 -0
- data/app/services/api_maker/index_command_service.rb +22 -0
- data/app/services/api_maker/js_method_namer_service.rb +11 -0
- data/app/services/api_maker/member_command_service.rb +25 -0
- data/app/services/api_maker/model_content_generator_service.rb +108 -0
- data/app/services/api_maker/models_finder_service.rb +22 -0
- data/app/services/api_maker/models_generator_service.rb +104 -0
- data/app/services/api_maker/update_command.rb +43 -0
- data/app/services/api_maker/update_command_service.rb +21 -0
- data/app/services/api_maker/valid_command.rb +35 -0
- data/app/services/api_maker/valid_command_service.rb +21 -0
- data/app/views/api_maker/_data.html.erb +15 -0
- data/config/rails_best_practices.yml +55 -0
- data/config/routes.rb +7 -0
- data/lib/api_maker.rb +36 -0
- data/lib/api_maker/ability.rb +39 -0
- data/lib/api_maker/ability_loader.rb +21 -0
- data/lib/api_maker/action_controller_base_extensions.rb +5 -0
- data/lib/api_maker/base_command.rb +81 -0
- data/lib/api_maker/base_resource.rb +78 -0
- data/lib/api_maker/collection_serializer.rb +69 -0
- data/lib/api_maker/command_spec_helper.rb +57 -0
- data/lib/api_maker/configuration.rb +34 -0
- data/lib/api_maker/engine.rb +5 -0
- data/lib/api_maker/individual_command.rb +37 -0
- data/lib/api_maker/javascript/api.js +92 -0
- data/lib/api_maker/javascript/base-model.js +543 -0
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +16 -0
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +47 -0
- data/lib/api_maker/javascript/bootstrap/card.jsx +79 -0
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +127 -0
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +105 -0
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +136 -0
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +80 -0
- data/lib/api_maker/javascript/bootstrap/select.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +203 -0
- data/lib/api_maker/javascript/cable-connection-pool.js +169 -0
- data/lib/api_maker/javascript/cable-subscription-pool.js +111 -0
- data/lib/api_maker/javascript/cable-subscription.js +33 -0
- data/lib/api_maker/javascript/collection.js +186 -0
- data/lib/api_maker/javascript/commands-pool.js +123 -0
- data/lib/api_maker/javascript/custom-error.js +14 -0
- data/lib/api_maker/javascript/deserializer.js +35 -0
- data/lib/api_maker/javascript/devise.js.erb +113 -0
- data/lib/api_maker/javascript/error-logger.js +119 -0
- data/lib/api_maker/javascript/event-connection.jsx +24 -0
- data/lib/api_maker/javascript/event-created.jsx +26 -0
- data/lib/api_maker/javascript/event-destroyed.jsx +26 -0
- data/lib/api_maker/javascript/event-emitter-listener.jsx +32 -0
- data/lib/api_maker/javascript/event-listener.jsx +41 -0
- data/lib/api_maker/javascript/event-updated.jsx +26 -0
- data/lib/api_maker/javascript/form-data-to-object.js +70 -0
- data/lib/api_maker/javascript/included.js +39 -0
- data/lib/api_maker/javascript/key-value-store.js +47 -0
- data/lib/api_maker/javascript/logger.js +23 -0
- data/lib/api_maker/javascript/model-name.js +21 -0
- data/lib/api_maker/javascript/model-template.js.erb +110 -0
- data/lib/api_maker/javascript/models-response-reader.js +43 -0
- data/lib/api_maker/javascript/paginate.jsx +128 -0
- data/lib/api_maker/javascript/params.js +68 -0
- data/lib/api_maker/javascript/resource-route.jsx +75 -0
- data/lib/api_maker/javascript/resource-routes.jsx +36 -0
- data/lib/api_maker/javascript/result.js +25 -0
- data/lib/api_maker/javascript/session-status-updater.js +113 -0
- data/lib/api_maker/javascript/sort-link.jsx +88 -0
- data/lib/api_maker/javascript/updated-attribute.jsx +60 -0
- data/lib/api_maker/loader.rb +14 -0
- data/lib/api_maker/memory_storage.rb +65 -0
- data/lib/api_maker/model_extensions.rb +96 -0
- data/lib/api_maker/permitted_params_argument.rb +12 -0
- data/lib/api_maker/preloader.rb +91 -0
- data/lib/api_maker/preloader_belongs_to.rb +58 -0
- data/lib/api_maker/preloader_has_many.rb +69 -0
- data/lib/api_maker/preloader_has_one.rb +70 -0
- data/lib/api_maker/preloader_through.rb +101 -0
- data/lib/api_maker/railtie.rb +14 -0
- data/lib/api_maker/relationship_includer.rb +42 -0
- data/lib/api_maker/resource_routing.rb +8 -0
- data/lib/api_maker/result_parser.rb +50 -0
- data/lib/api_maker/serializer.rb +86 -0
- data/lib/api_maker/spec_helper.rb +100 -0
- data/lib/api_maker/version.rb +3 -0
- data/lib/tasks/api_maker_tasks.rake +5 -0
- metadata +581 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
class ApiMaker::CreateCommandService < ApiMaker::CommandService
|
2
|
+
def execute
|
3
|
+
ApiMaker::CreateCommand.execute_in_thread!(
|
4
|
+
ability: ability,
|
5
|
+
args: args,
|
6
|
+
collection: collection,
|
7
|
+
commands: commands,
|
8
|
+
command_response: command_response,
|
9
|
+
controller: controller
|
10
|
+
)
|
11
|
+
|
12
|
+
ServicePattern::Response.new(success: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection
|
16
|
+
@collection ||= model_class.accessible_by(@ability, :create)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class ApiMaker::DestroyCommand < ApiMaker::BaseCommand
|
2
|
+
attr_reader :command, :model, :params, :serializer
|
3
|
+
|
4
|
+
def execute!
|
5
|
+
each_command do |command|
|
6
|
+
@command = command
|
7
|
+
@model = command.model
|
8
|
+
@params = command.args || {}
|
9
|
+
@serializer = serialized_resource(model)
|
10
|
+
|
11
|
+
if command.model.destroy
|
12
|
+
success_response
|
13
|
+
else
|
14
|
+
failure_response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
ServicePattern::Response.new(success: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def failure_response
|
22
|
+
command.fail(
|
23
|
+
model: serializer.result,
|
24
|
+
success: false,
|
25
|
+
errors: model.errors.full_messages
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialized_resource(model)
|
30
|
+
ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
|
31
|
+
end
|
32
|
+
|
33
|
+
def success_response
|
34
|
+
command.result(
|
35
|
+
model: serializer.result,
|
36
|
+
success: true
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ApiMaker::DestroyCommandService < ApiMaker::CommandService
|
2
|
+
def execute
|
3
|
+
ApiMaker::DestroyCommand.execute_in_thread!(
|
4
|
+
ability: ability,
|
5
|
+
args: args,
|
6
|
+
collection: collection,
|
7
|
+
commands: commands,
|
8
|
+
command_response: command_response,
|
9
|
+
controller: controller
|
10
|
+
)
|
11
|
+
|
12
|
+
ServicePattern::Response.new(success: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection
|
16
|
+
@collection ||= model_class.accessible_by(@ability, :destroy).where(model_class.primary_key => ids)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ids
|
20
|
+
@commands.values.map { |command| command.fetch("primary_key") }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
|
2
|
+
def execute
|
3
|
+
check_if_root_folder_defined
|
4
|
+
create_root_folder
|
5
|
+
create_model_files
|
6
|
+
|
7
|
+
ServicePattern::Response.new(success: true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def root_folder
|
11
|
+
@root_folder ||= ApiMaker::Configuration.current.react_native_path
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_if_root_folder_defined
|
15
|
+
raise "No root folder detected" if root_folder.blank?
|
16
|
+
|
17
|
+
Dir.mkdir(model_path) unless Dir.exist?(model_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_root_folder
|
21
|
+
Dir.mkdir(root_folder) unless Dir.exist?(root_folder)
|
22
|
+
end
|
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
|
+
def model_generator_service
|
39
|
+
@model_generator_service ||= ApiMaker::ModelsGeneratorService.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def model_file(model)
|
43
|
+
resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
|
44
|
+
File.join(model_path, "#{resource_class.short_name.underscore.dasherize}.js")
|
45
|
+
end
|
46
|
+
|
47
|
+
def model_path
|
48
|
+
@model_path ||= File.join(root_folder, "models")
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_base_model
|
52
|
+
files = %w[
|
53
|
+
api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js
|
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
|
56
|
+
]
|
57
|
+
path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
|
58
|
+
|
59
|
+
copy_base_files(files, path, root_folder)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class ApiMaker::IndexCommand < ApiMaker::BaseCommand
|
2
|
+
attr_reader :params
|
3
|
+
|
4
|
+
def execute!
|
5
|
+
ApiMaker::Configuration.profile("IndexCommand execute") do
|
6
|
+
each_command do |command|
|
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
|
34
|
+
|
35
|
+
def collection_from_query(collection)
|
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(
|
40
|
+
ability: current_ability,
|
41
|
+
args: api_maker_args,
|
42
|
+
collection: collection,
|
43
|
+
include_param: params[:include],
|
44
|
+
select: select
|
45
|
+
).result
|
46
|
+
end
|
47
|
+
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
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ApiMaker::IndexCommandService < ApiMaker::CommandService
|
2
|
+
def execute
|
3
|
+
ApiMaker::IndexCommand.execute_in_thread!(
|
4
|
+
ability: ability,
|
5
|
+
args: args,
|
6
|
+
collection: collection,
|
7
|
+
commands: commands,
|
8
|
+
command_response: command_response,
|
9
|
+
controller: controller
|
10
|
+
)
|
11
|
+
|
12
|
+
ServicePattern::Response.new(success: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection
|
16
|
+
@collection ||= model_class.accessible_by(@ability)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ids
|
20
|
+
@ids ||= @commands.values.map { |command| command.fetch("primary_key") }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ApiMaker::JsMethodNamerService < ApiMaker::ApplicationService
|
2
|
+
def initialize(name:)
|
3
|
+
@name = name
|
4
|
+
end
|
5
|
+
|
6
|
+
def execute
|
7
|
+
camelized = @name.to_s.camelize
|
8
|
+
new_name = "#{camelized[0..0].downcase}#{camelized[1..camelized.length]}"
|
9
|
+
ServicePattern::Response.new(result: new_name)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class ApiMaker::MemberCommandService < ApiMaker::CommandService
|
2
|
+
def execute
|
3
|
+
ability_name = @command_name.to_sym
|
4
|
+
collection = model_class.accessible_by(@ability, ability_name).where(model_class.primary_key => ids)
|
5
|
+
|
6
|
+
constant.execute_in_thread!(
|
7
|
+
ability: ability,
|
8
|
+
args: args,
|
9
|
+
collection: collection,
|
10
|
+
commands: commands,
|
11
|
+
command_response: command_response,
|
12
|
+
controller: controller
|
13
|
+
)
|
14
|
+
|
15
|
+
ServicePattern::Response.new(success: true)
|
16
|
+
end
|
17
|
+
|
18
|
+
def constant
|
19
|
+
@constant ||= "Commands::#{namespace}::#{@command_name.camelize}".constantize
|
20
|
+
end
|
21
|
+
|
22
|
+
def ids
|
23
|
+
@commands.values.map { |command| command.fetch("primary_key") }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
class ApiMaker::ModelContentGeneratorService < ApiMaker::ApplicationService
|
2
|
+
attr_reader :model
|
3
|
+
|
4
|
+
def initialize(model:)
|
5
|
+
@model = model
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute
|
9
|
+
if resource
|
10
|
+
ServicePattern::Response.new(result: model_content)
|
11
|
+
else
|
12
|
+
ServicePattern::Response.new(errors: ["No resource defined for #{model.name}"])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def attributes
|
19
|
+
resource._attributes.map do |attribute, _data|
|
20
|
+
{name: attribute, type: model_type(attribute)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def collection_commands
|
25
|
+
ApiMaker::Loader.load_everything
|
26
|
+
ApiMaker::MemoryStorage.current.storage_for(resource, :collection_commands)
|
27
|
+
end
|
28
|
+
|
29
|
+
def member_commands
|
30
|
+
ApiMaker::Loader.load_everything
|
31
|
+
ApiMaker::MemoryStorage.current.storage_for(resource, :member_commands)
|
32
|
+
end
|
33
|
+
|
34
|
+
def model_content
|
35
|
+
erb = ERB.new(File.read(model_template_path))
|
36
|
+
erb.filename = File.realpath(model_template_path)
|
37
|
+
erb.result(binding)
|
38
|
+
end
|
39
|
+
|
40
|
+
def model_template_path
|
41
|
+
File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript", "model-template.js.erb")
|
42
|
+
end
|
43
|
+
|
44
|
+
def model_type(attribute_name)
|
45
|
+
model_type = model.columns_hash[attribute_name.to_s]&.type
|
46
|
+
model_type = :money if monetized_attributes.include?(attribute_name.to_s)
|
47
|
+
model_type ||= :unknown
|
48
|
+
model_type
|
49
|
+
end
|
50
|
+
|
51
|
+
def monetized_attributes
|
52
|
+
@monetized_attributes ||= @model.try(:monetized_attributes).try(:map) { |attribute| attribute[0] } || []
|
53
|
+
end
|
54
|
+
|
55
|
+
def reflections
|
56
|
+
@reflections ||= resource._relationships.map do |name, _data|
|
57
|
+
reflection = model.reflections.values.find { |reflection_i| reflection_i.name == name }
|
58
|
+
raise "Couldnt find reflection by that name: #{name}" unless reflection
|
59
|
+
|
60
|
+
reflection
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def reflection_has_many_parameters(reflection)
|
65
|
+
{
|
66
|
+
reflectionName: reflection.name,
|
67
|
+
model: "{{this}}",
|
68
|
+
modelName: reflection.class_name,
|
69
|
+
modelClass: "{{modelClass}}",
|
70
|
+
targetPathName: "/api_maker/#{reflection.klass.model_name.route_key}"
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def reflection_has_many_parameters_query(reflection)
|
75
|
+
if reflection.options[:through]
|
76
|
+
{
|
77
|
+
params: {
|
78
|
+
through: {
|
79
|
+
model: model.name,
|
80
|
+
id: "{{id}}",
|
81
|
+
reflection: reflection.name
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
ransack: {
|
88
|
+
"#{reflection.foreign_key}_eq" => "{{id}}"
|
89
|
+
}
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def reflections_for_model_class_data
|
95
|
+
@reflections_for_model_class_data ||= reflections.map do |reflection|
|
96
|
+
{
|
97
|
+
className: reflection.class_name,
|
98
|
+
collectionName: ApiMaker::MemoryStorage.current.resource_for_model(reflection.klass).collection_name,
|
99
|
+
name: reflection.name,
|
100
|
+
macro: reflection.macro
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def resource
|
106
|
+
@resource ||= ApiMaker::MemoryStorage.current.resource_for_model(@model)
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ApiMaker::ModelsFinderService < ApiMaker::ApplicationService
|
2
|
+
def execute
|
3
|
+
ServicePattern::Response.new(result: models)
|
4
|
+
end
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def models
|
9
|
+
result = []
|
10
|
+
Dir.glob(Rails.root.join("app", "api_maker", "resources", "**", "*.rb")) do |model_path|
|
11
|
+
next unless model_path.start_with?(Rails.root.to_s)
|
12
|
+
|
13
|
+
path_name = model_path.gsub(/\A#{Regexp.escape(Rails.root.to_s)}\/app\/api_maker\/resources\//, "").gsub(/\.rb\Z/, "")
|
14
|
+
next if path_name == "application_resource"
|
15
|
+
|
16
|
+
resource_class = "Resources::#{path_name.classify}".constantize
|
17
|
+
result << resource_class.model_class
|
18
|
+
end
|
19
|
+
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class ApiMaker::ModelsGeneratorService < ApiMaker::ApplicationService
|
2
|
+
def execute
|
3
|
+
create_base_structure
|
4
|
+
copy_base_model
|
5
|
+
copy_base_controllers
|
6
|
+
|
7
|
+
models.each do |model|
|
8
|
+
next if ignore_model?(model)
|
9
|
+
|
10
|
+
model_content_response = ApiMaker::ModelContentGeneratorService.execute(model: model)
|
11
|
+
|
12
|
+
if model_content_response.success?
|
13
|
+
File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
|
14
|
+
else
|
15
|
+
puts model_content_response.errors.join(". ")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ApiMaker::GenerateReactNativeApiService.execute! if ApiMaker::Configuration.current.react_native_path.present?
|
20
|
+
ServicePattern::Response.new(success: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ignore_model?(model)
|
24
|
+
model.name.end_with?("::Translation") ||
|
25
|
+
model.name.start_with?("ActiveStorage::") ||
|
26
|
+
model.name.end_with?("::ApplicationRecord")
|
27
|
+
end
|
28
|
+
|
29
|
+
def models
|
30
|
+
ApiMaker::ModelsFinderService.execute!
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def api_maker_root_path
|
36
|
+
Rails.root.join("app", "javascript", "api-maker")
|
37
|
+
end
|
38
|
+
|
39
|
+
def controller_path
|
40
|
+
Rails.root.join("app", "controllers", "api_maker")
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy_base_controllers
|
44
|
+
files = %w[devise_controller.rb]
|
45
|
+
path = File.join(__dir__, "..", "..", "controllers", "api_maker")
|
46
|
+
target_path = Rails.root.join("app", "controllers", "api_maker")
|
47
|
+
|
48
|
+
copy_base_files(files, path, target_path)
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_base_model
|
52
|
+
files = %w[
|
53
|
+
api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js collection.js
|
54
|
+
commands-pool.js event-created.jsx custom-error.js deserializer.js devise.js event-destroyed.jsx event-emitter-listener.jsx event-listener.jsx
|
55
|
+
event-updated.jsx error-logger.js form-data-to-object.js included.js key-value-store.js logger.js model-name.js models-response-reader.js
|
56
|
+
params.js result.js event-connection.jsx paginate.jsx sort-link.jsx updated-attribute.jsx resource-routes.jsx resource-route.jsx
|
57
|
+
session-status-updater.js bootstrap/attribute-row.jsx bootstrap/attribute-rows.jsx bootstrap/card.jsx
|
58
|
+
bootstrap/checkbox.jsx bootstrap/checkboxes.jsx bootstrap/money-input.jsx bootstrap/radio-buttons.jsx
|
59
|
+
bootstrap/select.jsx bootstrap/string-input.jsx bootstrap/live-table.jsx
|
60
|
+
]
|
61
|
+
path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
|
62
|
+
target_path = api_maker_root_path
|
63
|
+
|
64
|
+
copy_base_files(files, path, target_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def copy_base_files(files, path, target_path)
|
68
|
+
files.each do |file|
|
69
|
+
base_model_source_path = File.join(path, file)
|
70
|
+
base_model_target_path = File.join(target_path, file)
|
71
|
+
|
72
|
+
base_model_target_dir = File.dirname(base_model_target_path)
|
73
|
+
FileUtils.mkdir_p(base_model_target_dir) unless File.exist?(base_model_target_dir)
|
74
|
+
|
75
|
+
if File.exist?(base_model_source_path)
|
76
|
+
content = File.read(base_model_source_path)
|
77
|
+
else
|
78
|
+
base_model_source_path << ".erb"
|
79
|
+
erb = ERB.new(File.read(base_model_source_path))
|
80
|
+
erb.filename = base_model_source_path
|
81
|
+
content = erb.result(binding)
|
82
|
+
end
|
83
|
+
|
84
|
+
base_model_target_path = File.join(target_path, file)
|
85
|
+
|
86
|
+
File.open(base_model_target_path, "w") do |fp|
|
87
|
+
fp.write(content)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_base_structure
|
93
|
+
# Dont remove all the files. It messes up running Webpack Dev Servers which forces you to restart all the time.
|
94
|
+
# FileUtils.rm_rf(api_maker_root_path) if File.exist?(api_maker_root_path)
|
95
|
+
|
96
|
+
FileUtils.mkdir_p(api_maker_root_path.join("models"))
|
97
|
+
FileUtils.mkdir_p(controller_path) unless File.exist?(controller_path)
|
98
|
+
end
|
99
|
+
|
100
|
+
def model_file(model)
|
101
|
+
resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
|
102
|
+
api_maker_root_path.join("models", "#{resource_class.short_name.underscore.dasherize}.js")
|
103
|
+
end
|
104
|
+
end
|