api_maker 0.0.1
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 +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
data/Rakefile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "bundler/setup"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require "rdoc/task"
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = "rdoc"
|
|
11
|
+
rdoc.title = "ApiMaker"
|
|
12
|
+
rdoc.options << "--line-numbers"
|
|
13
|
+
rdoc.rdoc_files.include("README.md")
|
|
14
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
|
18
|
+
load "rails/tasks/engine.rake"
|
|
19
|
+
|
|
20
|
+
load "rails/tasks/statistics.rake"
|
|
21
|
+
|
|
22
|
+
require "bundler/gem_tasks"
|
|
23
|
+
|
|
24
|
+
if Rails.env.development? || Rails.env.test?
|
|
25
|
+
require "best_practice_project"
|
|
26
|
+
BestPracticeProject.load_tasks
|
|
27
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
class ApiMaker::SubscriptionsChannel < ApplicationCable::Channel
|
|
2
|
+
def subscribed
|
|
3
|
+
params[:subscription_data].each do |model_name, subscription_types|
|
|
4
|
+
subscription_types["events"]&.each do |event_name, model_ids|
|
|
5
|
+
connect_event(model_name, model_ids, event_name)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
connect_creates(model_name) if subscription_types.key?("creates")
|
|
9
|
+
|
|
10
|
+
if subscription_types.key?("updates")
|
|
11
|
+
model_ids = subscription_types.fetch("updates")
|
|
12
|
+
connect_updates(model_name, model_ids)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
if subscription_types.key?("destroys")
|
|
16
|
+
model_ids = subscription_types.fetch("destroys")
|
|
17
|
+
connect_destroys(model_name, model_ids)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def connect_creates(model_name)
|
|
25
|
+
model_class = model_for_resource_name(model_name)
|
|
26
|
+
channel_name = model_class.api_maker_broadcast_create_channel_name
|
|
27
|
+
stream_from(channel_name, coder: ActiveSupport::JSON) do |data|
|
|
28
|
+
# We need to look the model up to evaluate if the user has access
|
|
29
|
+
model = data.fetch("model_class_name").safe_constantize.accessible_by(current_ability, :create_events).find(data.fetch("model_id"))
|
|
30
|
+
|
|
31
|
+
# Transmit the data to JS if its allowed
|
|
32
|
+
transmit data if model
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def connect_destroys(model_name, model_ids)
|
|
37
|
+
model_class = model_for_resource_name(model_name)
|
|
38
|
+
models = model_class.accessible_by(current_ability, :destroy_events).where(model_class.primary_key => model_ids)
|
|
39
|
+
models.each do |model|
|
|
40
|
+
channel_name = model.api_maker_broadcast_destroy_channel_name
|
|
41
|
+
stream_from(channel_name, coder: ActiveSupport::JSON) do |data|
|
|
42
|
+
transmit data
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def connect_event(model_name, model_ids, event_name)
|
|
48
|
+
ability_name = "event_#{event_name}".to_sym
|
|
49
|
+
model_class = model_for_resource_name(model_name)
|
|
50
|
+
models = model_class.accessible_by(current_ability, ability_name).where(model_class.primary_key => model_ids)
|
|
51
|
+
models.each do |model|
|
|
52
|
+
channel_name = model.api_maker_event_channel_name(event_name)
|
|
53
|
+
stream_from(channel_name, coder: ActiveSupport::JSON) do |data|
|
|
54
|
+
transmit data
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def connect_updates(model_name, model_ids)
|
|
60
|
+
model_class = model_for_resource_name(model_name)
|
|
61
|
+
models = model_class.accessible_by(current_ability, :update_events).where(model_class.primary_key => model_ids)
|
|
62
|
+
models.each do |model|
|
|
63
|
+
channel_name = model.api_maker_broadcast_update_channel_name
|
|
64
|
+
stream_from(channel_name, coder: ActiveSupport::JSON) do |data|
|
|
65
|
+
transmit data
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def model_for_resource_name(resource_name)
|
|
71
|
+
resource_for_resource_name(resource_name).model_class
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def resource_for_resource_name(resource_name)
|
|
75
|
+
resource = "Resources::#{resource_name}Resource".safe_constantize
|
|
76
|
+
raise "Cannot find resource by resource name: #{resource_name}" unless resource
|
|
77
|
+
|
|
78
|
+
resource
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class ApiMaker::BaseController < ApplicationController
|
|
2
|
+
protect_from_forgery with: :exception
|
|
3
|
+
|
|
4
|
+
before_action :set_locale
|
|
5
|
+
|
|
6
|
+
rescue_from Exception, with: :render_error
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def current_ability
|
|
11
|
+
@current_ability ||= ::ApiMaker::Ability.new(args: api_maker_args)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_error(error)
|
|
15
|
+
puts error.inspect
|
|
16
|
+
puts error.backtrace
|
|
17
|
+
|
|
18
|
+
logger.error error.inspect
|
|
19
|
+
logger.error error.backtrace.join("\n")
|
|
20
|
+
|
|
21
|
+
raise error
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def set_locale
|
|
25
|
+
return if session[:locale].blank?
|
|
26
|
+
|
|
27
|
+
locale = session[:locale].to_s
|
|
28
|
+
locale_exists = I18n.available_locales.map(&:to_s).include?(locale)
|
|
29
|
+
|
|
30
|
+
I18n.locale = locale if locale_exists
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class ApiMaker::CommandsController < ApiMaker::BaseController
|
|
2
|
+
def create
|
|
3
|
+
command_response = ApiMaker::CommandResponse.new(controller: self)
|
|
4
|
+
controller = self
|
|
5
|
+
|
|
6
|
+
params[:pool].each do |command_type, command_type_data|
|
|
7
|
+
command_type_data.each do |resource_plural_name, command_model_data|
|
|
8
|
+
command_model_data.each do |command_name, command_data|
|
|
9
|
+
ApiMaker.const_get("#{command_type.camelize}CommandService").execute!(
|
|
10
|
+
ability: current_ability,
|
|
11
|
+
args: api_maker_args,
|
|
12
|
+
command_response: command_response,
|
|
13
|
+
commands: command_data,
|
|
14
|
+
command_name: command_name,
|
|
15
|
+
resource_name: resource_plural_name,
|
|
16
|
+
controller: controller
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
command_response.join_threads
|
|
23
|
+
|
|
24
|
+
render json: {responses: command_response.result}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class ApiMaker::DeviseController < ApiMaker::BaseController
|
|
2
|
+
include Devise::Controllers::Rememberable
|
|
3
|
+
|
|
4
|
+
before_action :check_model_exists, only: :do_sign_in
|
|
5
|
+
before_action :check_serializer_exists, only: :do_sign_in
|
|
6
|
+
|
|
7
|
+
def do_sign_in
|
|
8
|
+
if !model.active_for_authentication?
|
|
9
|
+
render json: {success: false, errors: [model.inactive_message]}
|
|
10
|
+
elsif model.valid_password?(params[:password])
|
|
11
|
+
sign_in(model, scope: scope)
|
|
12
|
+
remember_me(model) if params.dig(:args, :rememberMe)
|
|
13
|
+
render json: {success: true, model_data: serializer.result}
|
|
14
|
+
else
|
|
15
|
+
render json: {success: false, errors: [invalid_error_message]}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def do_sign_out
|
|
20
|
+
scope = params.dig(:args, :scope).presence || "user"
|
|
21
|
+
current_model = __send__("current_#{scope}")
|
|
22
|
+
sign_out current_model
|
|
23
|
+
render json: {success: true}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def check_model_exists
|
|
29
|
+
error_msg = t("devise.failure.not_found_in_database", authentication_keys: model_class.authentication_keys.join(", "))
|
|
30
|
+
render json: {success: false, errors: [error_msg]} unless model
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check_serializer_exists
|
|
34
|
+
render json: {success: false, errors: ["Serializer doesn't exist for #{scope}"]} unless resource
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def invalid_error_message
|
|
38
|
+
t("devise.failure.invalid", authentication_keys: model_class.authentication_keys.join(", "))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def model
|
|
42
|
+
@model ||= model_class.find_for_authentication(email: params[:username])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def model_class
|
|
46
|
+
@model_class ||= scope.camelize.safe_constantize
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def scope
|
|
50
|
+
@scope ||= params.dig(:args, :scope).presence || "user"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def resource
|
|
54
|
+
@resource ||= ApiMaker::Serializer.resource_for(model.class)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def serializer
|
|
58
|
+
@serializer ||= ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class ApiMaker::SessionStatusesController < ActionController::Base
|
|
2
|
+
skip_before_action :verify_authenticity_token, raise: false
|
|
3
|
+
|
|
4
|
+
def create
|
|
5
|
+
scopes = {}
|
|
6
|
+
result = {
|
|
7
|
+
devise: {
|
|
8
|
+
timeout_in: Devise.timeout_in.to_i
|
|
9
|
+
},
|
|
10
|
+
csrf_token: form_authenticity_token,
|
|
11
|
+
scopes: scopes
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
Devise.mappings.each do |scope|
|
|
15
|
+
klass = scope[1].class_name.safe_constantize
|
|
16
|
+
param_key = klass.model_name.param_key
|
|
17
|
+
|
|
18
|
+
model_method_name = "current_#{param_key}"
|
|
19
|
+
model = __send__(model_method_name)
|
|
20
|
+
model_pk = model&.__send__(klass.primary_key)
|
|
21
|
+
|
|
22
|
+
signed_in_method_name = "#{param_key}_signed_in?"
|
|
23
|
+
signed_in = __send__(signed_in_method_name)
|
|
24
|
+
|
|
25
|
+
scopes[param_key] = {
|
|
26
|
+
primary_key: model_pk,
|
|
27
|
+
signed_in: signed_in
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
render json: result
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class ApiMaker::CollectionCommandService < ApiMaker::CommandService
|
|
2
|
+
def execute
|
|
3
|
+
authorize!
|
|
4
|
+
|
|
5
|
+
constant.execute_in_thread!(
|
|
6
|
+
ability: ability,
|
|
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)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def authorize!
|
|
18
|
+
raise CanCan::AccessDenied, "No access to '#{@command_name}' on '#{model_class.name}'" unless @ability.can?(@command_name.to_sym, model_class)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def constant
|
|
22
|
+
@constant ||= "Commands::#{namespace}::#{@command_name.camelize}".constantize
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
class ApiMaker::CommandResponse
|
|
2
|
+
attr_reader :controller, :locale, :result
|
|
3
|
+
|
|
4
|
+
def initialize(controller:)
|
|
5
|
+
@controller = controller
|
|
6
|
+
@locale = I18n.locale
|
|
7
|
+
@mutex = Mutex.new
|
|
8
|
+
@result = {}
|
|
9
|
+
@threads = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def error_for_command(id, data)
|
|
13
|
+
respond_to_command(id, data, :error)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fail_for_command(id, data)
|
|
17
|
+
respond_to_command(id, data, :failed)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def result_for_command(id, data)
|
|
21
|
+
respond_to_command(id, data, :success)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def join_threads
|
|
25
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
|
26
|
+
@threads.each(&:join)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def respond_to_command(id, data, type)
|
|
31
|
+
@mutex.synchronize do
|
|
32
|
+
@result[id] = {type: type, data: data}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def threadding?
|
|
37
|
+
ApiMaker::Configuration.current.threadding
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def with_thread(&blk)
|
|
41
|
+
if Rails.env.test? || !threadding?
|
|
42
|
+
yield
|
|
43
|
+
else
|
|
44
|
+
spawn_thread(&blk)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def spawn_thread
|
|
51
|
+
@threads << Thread.new do
|
|
52
|
+
Rails.application.executor.wrap do
|
|
53
|
+
I18n.with_locale(locale) do
|
|
54
|
+
yield
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
|
58
|
+
puts e.inspect
|
|
59
|
+
puts e.backtrace
|
|
60
|
+
|
|
61
|
+
Rails.logger.error e.message
|
|
62
|
+
Rails.logger.error e.backtrace.join("\n")
|
|
63
|
+
|
|
64
|
+
ApiMaker::Configuration.current.report_error(controller: controller, error: e)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class ApiMaker::CommandService < ApiMaker::ApplicationService
|
|
2
|
+
attr_reader :ability, :args, :commands, :command_name, :command_response, :controller, :resource_name
|
|
3
|
+
|
|
4
|
+
def initialize(ability:, args:, commands:, command_name:, command_response:, controller:, resource_name:)
|
|
5
|
+
@ability = ability
|
|
6
|
+
@args = args
|
|
7
|
+
@command_name = command_name
|
|
8
|
+
@command_response = command_response
|
|
9
|
+
@commands = commands
|
|
10
|
+
@controller = controller
|
|
11
|
+
@resource_name = resource_name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def namespace
|
|
15
|
+
@namespace ||= resource_name.underscore.camelize
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def resource
|
|
19
|
+
@resource ||= begin
|
|
20
|
+
resource_class_name = "Resources::#{resource_name.underscore.singularize.camelize}Resource"
|
|
21
|
+
resource = resource_class_name.safe_constantize
|
|
22
|
+
raise "Couldnt find resource from resource name: #{resource_class_name}" unless resource
|
|
23
|
+
|
|
24
|
+
resource
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def model_class
|
|
29
|
+
@model_class ||= resource.model_class
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class ApiMaker::CreateCommand < ApiMaker::BaseCommand
|
|
2
|
+
attr_reader :command, :model, :params, :serializer
|
|
3
|
+
|
|
4
|
+
def execute!
|
|
5
|
+
each_command do |command|
|
|
6
|
+
@command = command
|
|
7
|
+
@model = collection.klass.new
|
|
8
|
+
@params = command.args || {}
|
|
9
|
+
@serializer = serialized_resource(model)
|
|
10
|
+
@model.assign_attributes(sanitize_parameters)
|
|
11
|
+
|
|
12
|
+
if !current_ability.can?(:create, @model)
|
|
13
|
+
failure_response(["No access to create that resource"])
|
|
14
|
+
elsif @model.save
|
|
15
|
+
success_response
|
|
16
|
+
else
|
|
17
|
+
failure_response(model.errors.full_messages)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
ServicePattern::Response.new(success: true)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def api_maker_resource_class
|
|
25
|
+
@api_maker_resource_class ||= "Resources::#{collection.klass.name}Resource".constantize
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def failure_response(errors)
|
|
29
|
+
command.fail(
|
|
30
|
+
model: serializer.result,
|
|
31
|
+
success: false,
|
|
32
|
+
errors: errors
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def resource_instance_class_name
|
|
37
|
+
@resource_instance_class_name ||= self.class.name.split("::").last.gsub(/Controller$/, "").singularize
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def resource_instance_class
|
|
41
|
+
@resource_instance_class ||= api_maker_resource_class.model_class
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def resource_variable_name
|
|
45
|
+
@resource_variable_name ||= resource_instance_class_name.underscore.parameterize
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sanitize_parameters
|
|
49
|
+
serializer.resource_instance.permitted_params(ApiMaker::PermittedParamsArgument.new(command: command, model: model))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def serialized_resource(model)
|
|
53
|
+
ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def success_response
|
|
57
|
+
command.result(
|
|
58
|
+
model: serializer.result,
|
|
59
|
+
success: true
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
end
|