tramway-api 1.7.1.2 → 1.8.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da48436e048ba6df03c3764a6e528da5f427c1fbac6b61f38d518c716f19ec78
4
- data.tar.gz: b2ab9a5eb94df23ed37869e6908ae0c8fcf469816095e04fd9483fe986694247
3
+ metadata.gz: 56cacd097b745beaad7a04f1b31a63f645ffcb0ca3f2705be6c636765e04968a
4
+ data.tar.gz: 30b2598b412f3b87d48895254e1eef6ffd8b1c20299ea07b9bee766397aff8a5
5
5
  SHA512:
6
- metadata.gz: cc0856fcd9f84958606c305180ab4c719d3861e28e0f620e75630eac665e87c08f67021a953318380ba09d91876e2809a42d33a05dbf12fe3fb7cf11ce2267ff
7
- data.tar.gz: c551fdb3f5f9d42baf32de1f4e05e3ad12a2d8cbff675b5d4a6c521febcac17e0635f5cee7d2338c3fbbddb77d9936b8ef14060b7b4d7fd1c71febd4825a2337
6
+ metadata.gz: 42275c0a399c5f988e6cbf683a03b1eacbf3aae1da85a212ef06f48e936ed9e0a856ba89132d80e4c4f11e49a620f4cb8a7f2ee2402857ac24a4e5d2772f46c5
7
+ data.tar.gz: ae1465d070ee21a997310922cd43898617a617d5d74a727e4a37abd6717aca961ca833c547038703738227f2c9559e295dcd3c7bdcf191893b1957f95c962964
@@ -19,6 +19,105 @@ module Tramway
19
19
  end
20
20
  hash
21
21
  end
22
+
23
+ private
24
+
25
+ def record
26
+ @record = model_class.find_by! uuid: params[:id] if params[:id].present?
27
+ end
28
+
29
+ def records
30
+ collection = model_class.active.order(id: :desc).send params[:scope] || :all
31
+ collection = collection.full_text_search params[:search] if params[:search]
32
+ collection
33
+ end
34
+
35
+ def check_available_model_class
36
+ unless model_class
37
+ head(:unauthorized) && return unless current_user
38
+ head(:unprocessable_entity) && return
39
+ end
40
+ end
41
+
42
+ def check_available_model_action_for_record
43
+ action_is_available = check_action
44
+ action_is_available.tap do
45
+ if action_is_available.is_a?(Proc) && !action_is_available.call(record, current_user)
46
+ head(:unprocessable_entity) && return
47
+ end
48
+ end
49
+ end
50
+
51
+ def available_action_for_collection
52
+ action_is_available = check_action
53
+ return records if action_is_available == true
54
+
55
+ action_is_available.call records, current_user if action_is_available.is_a?(Proc)
56
+ end
57
+
58
+ def check_action
59
+ action_is_available = checking_roles.map do |role|
60
+ Tramway::Api.action_is_available(
61
+ action: action_name.to_sym,
62
+ project: (@application_engine || @application.name),
63
+ role: role,
64
+ model_name: params[:model],
65
+ current_user: current_user
66
+ )
67
+ end.compact.uniq - [false]
68
+
69
+ if action_is_available.count > 1
70
+ Tramway::Error.raise_error(:tramway, :api, :api, :v1, :records_controller, :available_action_for_collection, :duplicate_actions)
71
+ end
72
+
73
+ action_is_available = action_is_available.first
74
+
75
+ action_is_available.tap do
76
+ head(:unprocessable_entity) && return unless action_is_available
77
+ end
78
+ end
79
+
80
+ def authenticate_user_if_needed
81
+ action_is_open = Tramway::Api.action_is_available(
82
+ action: action_name.to_sym,
83
+ project: (@application_engine || @application.name),
84
+ model_name: params[:model]
85
+ )
86
+ head(:unauthorized) && return if !current_user && !action_is_open
87
+ end
88
+
89
+ def available_models_for_current_user
90
+ checking_roles.reduce([]) do |models, role|
91
+ models += ::Tramway::Api.available_models(role: role).map(&:to_s)
92
+ end
93
+ end
94
+
95
+ def checking_roles
96
+ [:open, current_user&.role].compact
97
+ end
98
+ protected
99
+
100
+ def model_class
101
+ if params[:model].to_s.in? available_models_for_current_user
102
+ begin
103
+ params[:model].constantize
104
+ rescue ActiveSupport::Concern::MultipleIncludedBlocks => e
105
+ raise "#{e}. Maybe #{params[:model]} model doesn't exists or there is naming conflicts with it"
106
+ end
107
+ end
108
+ end
109
+
110
+ def decorator_class(model_name = nil)
111
+ "#{model_name || model_class}Decorator".constantize
112
+ end
113
+
114
+ def form_class(model_name = nil)
115
+ "#{model_name || model_class}Form".constantize
116
+ end
117
+
118
+ def serializer_class(model_name = nil)
119
+ "#{model_name || model_class}Serializer".constantize
120
+ end
22
121
  end
23
122
  end
24
123
  end
@@ -3,13 +3,13 @@
3
3
  module Tramway::Api::V1
4
4
  class RecordsController < ::Tramway::Api::V1::ApplicationController
5
5
  before_action :check_available_model_class
6
- before_action :check_available_model_action
6
+ before_action :check_available_model_action_for_record, only: %i[show update destroy]
7
7
  before_action :authenticate_user_if_needed
8
8
 
9
9
  def index
10
- records = model_class.active.order(id: :desc).send params[:scope] || :all
11
- records = records.full_text_search params[:search] if params[:search]
12
- render json: records,
10
+ collection = available_action_for_collection
11
+
12
+ render json: collection,
13
13
  each_serializer: serializer_class,
14
14
  include: '*',
15
15
  status: :ok
@@ -29,7 +29,7 @@ module Tramway::Api::V1
29
29
  end
30
30
 
31
31
  def update
32
- record_form = form_class.new model_class.active.find_by! uuid: params[:id]
32
+ record_form = form_class.new record
33
33
  if record_form.submit snake_case params[:data][:attributes]
34
34
  render json: record_form.model,
35
35
  serializer: serializer_class,
@@ -41,7 +41,6 @@ module Tramway::Api::V1
41
41
  end
42
42
 
43
43
  def show
44
- record = model_class.active.find_by! uuid: params[:id]
45
44
  render json: record,
46
45
  serializer: serializer_class,
47
46
  include: '*',
@@ -49,52 +48,11 @@ module Tramway::Api::V1
49
48
  end
50
49
 
51
50
  def destroy
52
- record = model_class.active.find_by! uuid: params[:id]
53
51
  record.remove
54
52
  render json: record,
55
53
  serializer: serializer_class,
56
54
  include: '*',
57
55
  status: :no_content
58
56
  end
59
-
60
- private
61
-
62
- def check_available_model_class
63
- head(:unprocessable_entity) && return unless model_class
64
- end
65
-
66
- def check_available_model_action
67
- open_actions = Tramway::Api.available_models[model_class.to_s][:open]&.map(&:to_s) || []
68
- closed_actions = Tramway::Api.available_models[model_class.to_s][:closed]&.map(&:to_s) || []
69
- head(:unprocessable_entity) && return unless action_name.in? open_actions + closed_actions
70
- end
71
-
72
- def authenticate_user_if_needed
73
- if action_name.in?(Tramway::Api.available_models[model_class.to_s][:closed]&.map(&:to_s) || []) && !current_user
74
- head(:unauthorized) && return
75
- end
76
- end
77
-
78
- def model_class
79
- if params[:model].to_s.in? ::Tramway::Api.available_models.keys.map(&:to_s)
80
- begin
81
- params[:model].constantize
82
- rescue ActiveSupport::Concern::MultipleIncludedBlocks => e
83
- raise "#{e}. Maybe #{params[:model]} model doesn't exists or there is naming conflicts with it"
84
- end
85
- end
86
- end
87
-
88
- def decorator_class(model_name = nil)
89
- "#{model_name || model_class}Decorator".constantize
90
- end
91
-
92
- def form_class(model_name = nil)
93
- "#{model_name || model_class}Form".constantize
94
- end
95
-
96
- def serializer_class(model_name = nil)
97
- "#{model_name || model_class}Serializer".constantize
98
- end
99
57
  end
100
58
  end
@@ -3,7 +3,7 @@
3
3
  require 'tramway/helpers/class_name_helpers'
4
4
 
5
5
  class Tramway::Api::V1::UsersController < ::Tramway::Api::V1::ApplicationController
6
- before_action :authenticate_user, only: :show
6
+ before_action :authenticate, only: :show
7
7
  include Tramway::ClassNameHelpers
8
8
 
9
9
  def create
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'tramway/api/engine'
4
+ require 'tramway/api/records_models'
5
+ require 'tramway/api/singleton_models'
4
6
 
5
7
  module Tramway
6
8
  module Api
7
9
  class << self
10
+ include ::Tramway::Api::RecordsModels
11
+ include ::Tramway::Api::SingletonModels
12
+
8
13
  def auth_config
9
14
  @@auth_config ||= [{ user_model: ::Tramway::User::User, auth_attributes: :email }]
10
15
  end
@@ -31,16 +36,52 @@ module Tramway
31
36
  end
32
37
  end
33
38
 
34
- def set_available_models(**models)
35
- @@available_models ||= {}
36
- models = models.reduce({}) do |hash, pair|
37
- hash.merge! pair[0].to_s.camelize => pair[1]
39
+ def get_models_by_key(checked_models, project, role)
40
+ unless project.present?
41
+ error = Tramway::Error.new(
42
+ plugin: :admin,
43
+ method: :get_models_by_key,
44
+ message: "Looks like you have not create at lease one instance of #{Tramway::Core.application.model_class} model"
45
+ )
46
+ raise error.message
47
+ end
48
+ checked_models && checked_models != [] && checked_models[project][role]&.keys || []
49
+ end
50
+
51
+ def models_array(models_type:, role:)
52
+ instance_variable_get("@#{models_type}_models")&.map do |projects|
53
+ projects.last[role]&.keys
54
+ end&.flatten || []
55
+ end
56
+
57
+ def action_is_available(project:, role: :open, model_name:, action:, current_user: nil)
58
+ actions = select_actions(project: project, role: role, model_name: model_name)
59
+ if actions.present? && !actions.is_a?(Array)
60
+ raise "Looks like you did not used array type to define action permissions. Remember it should be this way: `#{model_name} => [ :#{action} ]` or `#{model_name} => [ { #{action}: lambda { |record, current_user| your_condition } } ]`"
38
61
  end
39
- @@available_models.merge! models
62
+
63
+ availability = actions&.select do |a|
64
+ if a.is_a? Symbol
65
+ a == action.to_sym
66
+ elsif a.is_a? Hash
67
+ a.keys.first.to_sym == action.to_sym
68
+ end
69
+ end&.first
70
+
71
+ return false unless availability.present?
72
+ return true if availability.is_a? Symbol
73
+
74
+ availability.values.first
40
75
  end
41
76
 
42
- def available_models
43
- @@available_models ||= {}
77
+ def select_actions(project:, role:, model_name:)
78
+ stringify_keys(@singleton_models&.dig(project, role))&.dig(model_name) || stringify_keys(@available_models&.dig(project, role))&.dig(model_name)
79
+ end
80
+
81
+ def stringify_keys(hash)
82
+ hash&.reduce({}) do |new_hash, pair|
83
+ new_hash.merge! pair[0].to_s => pair[1]
84
+ end
44
85
  end
45
86
  end
46
87
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Api::RecordsModels
4
+ def set_available_models(*models, project:, role: :open)
5
+ @available_models ||= {}
6
+ @available_models[project] ||= {}
7
+ @available_models[project][role] ||= {}
8
+ models.each do |model|
9
+ if model.class == Class
10
+ @available_models[project][role].merge! model => %i[index show update create destroy]
11
+ elsif model.class == Hash
12
+ @available_models[project][role].merge! model
13
+ end
14
+ end
15
+ @available_models = @available_models.with_indifferent_access
16
+ end
17
+
18
+ def available_models_for(project, role: :open)
19
+ models = get_models_by_key(@available_models, project, role)
20
+ if project_is_engine?(project)
21
+ models += engine_class(project).dependencies.map do |dependency|
22
+ if @available_models&.dig(dependency, role).present?
23
+ @available_models&.dig(dependency, role).keys
24
+ else
25
+ error = Tramway::Error.new(
26
+ plugin: :admin,
27
+ method: :available_models_for,
28
+ message: "There is no dependency `#{dependency}` for plugin: #{project}. Please, check file `tramway-#{project}/lib/tramway/#{project}/#{project}.rb`"
29
+ )
30
+ raise error
31
+ end
32
+ end.flatten.compact
33
+ end
34
+ models
35
+ end
36
+
37
+ def available_models(role:)
38
+ models_array models_type: :available, role: role
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway::Api::SingletonModels
4
+ def set_singleton_models(*models, project:, role: :open)
5
+ @singleton_models ||= {}
6
+ @singleton_models[project] ||= {}
7
+ @singleton_models[project][role] ||= {}
8
+ models.each do |model|
9
+ if model.class == Class
10
+ @singleton_models[project][role].merge! model => %i[index show update create destroy]
11
+ elsif model.class == Hash
12
+ @singleton_models[project][role].merge! model
13
+ end
14
+ end
15
+ @singleton_models = @singleton_models.with_indifferent_access
16
+ end
17
+
18
+ def singleton_models_for(project, role: :open)
19
+ models = get_models_by_key(@singleton_models, project, role)
20
+ if project_is_engine?(project)
21
+ models += engine_class(project).dependencies.map do |dependency|
22
+ @singleton_models&.dig(dependency, role)&.keys
23
+ end.flatten.compact
24
+ end
25
+ models
26
+ end
27
+
28
+ def singleton_models(role:)
29
+ models_array models_type: :singleton, role: role
30
+ end
31
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Tramway
4
4
  module Api
5
- VERSION = '1.7.1.2'
5
+ VERSION = '1.8.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1.2
4
+ version: 1.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Kalashnikov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-08 00:00:00.000000000 Z
11
+ date: 2020-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -81,6 +81,8 @@ files:
81
81
  - lib/tasks/tramway/api_tasks.rake
82
82
  - lib/tramway/api.rb
83
83
  - lib/tramway/api/engine.rb
84
+ - lib/tramway/api/records_models.rb
85
+ - lib/tramway/api/singleton_models.rb
84
86
  - lib/tramway/api/version.rb
85
87
  homepage: https://github.com/kalashnikovisme/tramway-dev
86
88
  licenses: []