api_engine_base 0.1.1 → 0.1.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -6
  3. data/app/controllers/api_engine_base/admin_controller.rb +104 -0
  4. data/app/controllers/api_engine_base/application_controller.rb +45 -11
  5. data/app/controllers/api_engine_base/auth/plain_text_controller.rb +1 -1
  6. data/app/controllers/api_engine_base/user_controller.rb +49 -0
  7. data/app/models/api_engine_base/application_record.rb +38 -0
  8. data/app/models/user.rb +13 -4
  9. data/app/services/api_engine_base/README.md +49 -0
  10. data/app/services/api_engine_base/argument_validation/README.md +192 -0
  11. data/app/services/api_engine_base/argument_validation/class_methods.rb +2 -3
  12. data/app/services/api_engine_base/argument_validation/instance_methods.rb +13 -1
  13. data/app/services/api_engine_base/authorize/validate.rb +49 -0
  14. data/app/services/api_engine_base/jwt/authenticate_user.rb +22 -7
  15. data/app/services/api_engine_base/jwt/login_create.rb +1 -1
  16. data/app/services/api_engine_base/service_base.rb +4 -5
  17. data/app/services/api_engine_base/user_attributes/modify.rb +68 -0
  18. data/app/services/api_engine_base/user_attributes/roles.rb +27 -0
  19. data/config/routes.rb +11 -0
  20. data/db/migrate/20241117043720_create_api_engine_base_users.rb +2 -0
  21. data/lib/api_engine_base/authorization/default.yml +34 -0
  22. data/lib/api_engine_base/authorization/entity.rb +101 -0
  23. data/lib/api_engine_base/authorization/role.rb +101 -0
  24. data/lib/api_engine_base/authorization.rb +85 -0
  25. data/lib/api_engine_base/configuration/admin/config.rb +18 -0
  26. data/lib/api_engine_base/configuration/application/config.rb +2 -2
  27. data/lib/api_engine_base/configuration/authorization/config.rb +24 -0
  28. data/lib/api_engine_base/configuration/config.rb +19 -1
  29. data/lib/api_engine_base/configuration/user/config.rb +56 -0
  30. data/lib/api_engine_base/engine.rb +38 -6
  31. data/lib/api_engine_base/error.rb +5 -0
  32. data/lib/api_engine_base/schema/admin/users.rb +15 -0
  33. data/lib/api_engine_base/schema/error/invalid_argument_response.rb +1 -1
  34. data/lib/api_engine_base/schema/page.rb +14 -0
  35. data/lib/api_engine_base/schema/user.rb +28 -0
  36. data/lib/api_engine_base/schema.rb +5 -0
  37. data/lib/api_engine_base/spec_helper.rb +4 -3
  38. data/lib/api_engine_base/version.rb +1 -1
  39. data/lib/api_engine_base.rb +2 -2
  40. metadata +22 -4
@@ -9,6 +9,9 @@ require "api_engine_base/configuration/login/config"
9
9
  require "api_engine_base/configuration/otp/config"
10
10
  require "api_engine_base/configuration/username/config"
11
11
  require "api_engine_base/configuration/application/config"
12
+ require "api_engine_base/configuration/admin/config"
13
+ require "api_engine_base/configuration/authorization/config"
14
+ require "api_engine_base/configuration/user/config"
12
15
 
13
16
  module ApiEngineBase
14
17
  module Configuration
@@ -48,9 +51,24 @@ module ApiEngineBase
48
51
  # allow shorthand to be used
49
52
  alias_method :app, :application
50
53
 
54
+ add_composer :authorization,
55
+ desc: "Authorization via rbac configurations",
56
+ allowed: Configuration::Authorization::Config,
57
+ default: Configuration::Authorization::Config.new
58
+
59
+ add_composer :user,
60
+ desc: "User configuration for the app. Includes what to display and what attributes can be changed",
61
+ allowed: Configuration::User::Config,
62
+ default: Configuration::User::Config.new
63
+
64
+ add_composer :admin,
65
+ desc: "Admin configuration for the app",
66
+ allowed: Configuration::Admin::Config,
67
+ default: Configuration::Admin::Config.new
68
+
51
69
  # To be Deleted
52
70
  add_composer :otp,
53
- desc: "One Time Password generator is used for all Code validation. This describes defaults not set in other configurations",
71
+ desc: "One Time Password generation is used for ease in quickly validating a users actions. This is good for short term validation requirements as opposed to UserSecrets",
54
72
  allowed: Configuration::Otp::Config,
55
73
  default: Configuration::Otp::Config.new
56
74
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+
5
+ module ApiEngineBase
6
+ module Configuration
7
+ module User
8
+ class Config
9
+ include ClassComposer::Generator
10
+
11
+ ATTRIBUTES_TO_CHANGE = [
12
+ :email,
13
+ :first_name,
14
+ :last_name,
15
+ :last_known_timezone,
16
+ :username,
17
+ :verifier_token,
18
+ ]
19
+
20
+ ATTRIBUTES_TO_SHOW = [
21
+ *ATTRIBUTES_TO_CHANGE,
22
+ :id,
23
+ :roles,
24
+ :created_at,
25
+ ]
26
+
27
+ ATTRIBUTES_CHANGE_EXECUTE = Proc.new do |key, value|
28
+ ApiEngineBase::UserAttributes::Modify.assign!
29
+ end
30
+
31
+ ATTRIBUTES_SHOWN_EXECUTE = Proc.new do |key, value|
32
+ ApiEngineBase::Schema::User.assign!
33
+ end
34
+
35
+ add_composer :additional_attributes_for_change,
36
+ desc: "On top of the default attributes to change, this adds additional values for the user to change on their account",
37
+ allowed: Array,
38
+ default: [],
39
+ default_shown: "[]"
40
+
41
+ add_composer :default_attributes_for_change,
42
+ desc: "[Not Recommended for change] Default attributes that are allowed to change",
43
+ allowed: Array,
44
+ default: ATTRIBUTES_TO_CHANGE,
45
+ &ATTRIBUTES_CHANGE_EXECUTE
46
+
47
+ add_composer :default_attributes,
48
+ desc: "[Not Recommended for change] Default attributes that are shown to the user",
49
+ allowed: Array,
50
+ default_shown: ATTRIBUTES_TO_SHOW,
51
+ dynamic_default: -> (instance) { (ATTRIBUTES_TO_SHOW + instance.additional_attributes_for_change).uniq },
52
+ &ATTRIBUTES_SHOWN_EXECUTE
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "api_engine_base/authorization"
3
4
  require "api_engine_base/schema"
4
5
 
5
6
  module ApiEngineBase
@@ -8,14 +9,45 @@ module ApiEngineBase
8
9
 
9
10
  # Run after Rails loads the initializes and environment files
10
11
  # Ensures User has already set their desired config before we lock this down
11
- initializer "api_engine_base.config.instantiate", after: :load_config_initializers do |_app|
12
- # ensure defaults are instantiated and all variables are assigned
13
- ApiEngineBase.config.class_composer_assign_defaults!(children: true)
12
+ config.after_initialize do
13
+ db_rake_task = defined?(Rake) && (Rake.application.top_level_tasks.any? { |task| task =~ /db:/ } rescue nil)
14
+ if db_rake_task
15
+ # Because we call the Database during configuration setup,
16
+ # We want to skip calling the DB during a DB migration
17
+ else
18
+ # ensure defaults are instantiated and all variables are assigned
19
+ ApiEngineBase.config.class_composer_assign_defaults!(children: true)
14
20
 
15
- unless Rails.env.test?
16
- # Now that we can confirm all variables are defined, freeze all objects an their children
17
- ApiEngineBase.config.class_composer_freeze_objects!(behavior: :raise, children: true)
21
+ unless Rails.env.test?
22
+ # Now that we can confirm all variables are defined, freeze all objects an their children
23
+ ApiEngineBase.config.class_composer_freeze_objects!(behavior: :raise, children: true)
24
+ end
18
25
  end
19
26
  end
27
+
28
+
29
+ ####
30
+ # Bug: @matt-taylor
31
+ # RBAC code memoizes the controller object into a class variable
32
+ # In development when code changes, all classes get reloaded
33
+ # Inherently, this causes the `object_id` of the class to change
34
+ # This means the memoized class is no longer equal to the newly reloaded class
35
+ # NOTE: This is only a problem on reload! in development. Not an issue in Production
36
+ # Once this is fixed, it can go into a regular initializer and does not need to get re-computed on each reload
37
+ ###
38
+ # Potential solution:
39
+ # => Don't store the object as the comparison key
40
+ # => Or...When doing comparisons, convert everything to a string for comparison
41
+ # Changes to names should be infrequent/should have a full app restart
42
+
43
+ # Add all RBAC based role definitions prior to fork/loading
44
+ # Load once use forever
45
+ config.to_prepare do
46
+ ApiEngineBase::Authorization::Role.roles_reset!
47
+ ApiEngineBase::Authorization::Entity.entities_reset!
48
+ ApiEngineBase::Authorization.mapped_controllers_reset!
49
+
50
+ ApiEngineBase::Authorization.default_defined!
51
+ end
20
52
  end
21
53
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "api_engine_base/schema/user"
4
+ require "api_engine_base/schema/page"
5
+
6
+ module ApiEngineBase
7
+ module Schema
8
+ module Admin
9
+ class Users < JsonSchematize::Generator
10
+ add_field name: :users, array_of_types: true, type: ApiEngineBase::Schema::User
11
+ add_field name: :pagination, type: ApiEngineBase::Schema::Page, required: false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -9,7 +9,7 @@ module ApiEngineBase
9
9
  add_field name: :message, type: String, required: true
10
10
  add_field name: :status, type: String, required: true
11
11
  add_field name: :invalid_arguments, array_of_types: true, type: InvalidArgument
12
- add_field name: :invalid_argument_keys, type: Array
12
+ add_field name: :invalid_argument_keys, type: Array
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase
4
+ module Schema
5
+ class Page < JsonSchematize::Generator
6
+ schema_default option: :dig_type, value: :string
7
+
8
+ add_field name: :count, type: Integer
9
+ add_field name: :cursor, type: Integer
10
+ add_field name: :limit, type: Integer
11
+ add_field name: :next, type: String
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase
4
+ module Schema
5
+ class User < JsonSchematize::Generator
6
+ schema_default option: :dig_type, value: :string
7
+
8
+ def self.convert_user_object(user:)
9
+ attributes = ApiEngineBase.config.user.default_attributes.map(&:to_s)
10
+ object = user.attributes.slice(*attributes)
11
+
12
+ new(object)
13
+ end
14
+
15
+ # Gets assigned during configuration phase via
16
+ # lib/api_engine_base/configuration/user/config.rb
17
+ def self.assign!
18
+ attributes = ApiEngineBase.config.user.default_attributes
19
+ attributes.each do |attribute|
20
+ if metadata = ::User.attribute_to_type_mapping[attribute]
21
+ type = metadata[:serialized_type] ? metadata[:serialized_type] : metadata[:base]
22
+ add_field(name: attribute, type:)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -21,5 +21,10 @@ module ApiEngineBase
21
21
 
22
22
  require "api_engine_base/schema/plain_text/login_request"
23
23
  require "api_engine_base/schema/plain_text/login_response"
24
+
25
+ require "api_engine_base/schema/admin/users"
26
+
27
+ require "api_engine_base/schema/user"
28
+ require "api_engine_base/schema/page"
24
29
  end
25
30
  end
@@ -2,17 +2,18 @@
2
2
 
3
3
  module ApiEngineBase
4
4
  module SpecHelper
5
- def set_jwt_token!(user:, token: nil)
5
+ def set_jwt_token!(user:, with_reset: false, token: nil)
6
6
  if token.nil?
7
7
  result = ApiEngineBase::Jwt::LoginCreate.(user:)
8
8
  token = result.token
9
9
  end
10
10
 
11
- @request.headers[ApiEngineBase::ApplicationController::AUTHORIZATION_HEADER] = "Bearer: #{token}"
11
+ @request.headers[ApiEngineBase::ApplicationController::AUTHENTICATION_HEADER] = "Bearer: #{token}"
12
+ @request.headers[ApiEngineBase::ApplicationController::AUTHENTICATION_WITH_RESET] = "true" if with_reset
12
13
  end
13
14
 
14
15
  def unset_jwt_token!
15
- @request.headers[ApiEngineBase::ApplicationController::AUTHORIZATION_HEADER] = nil
16
+ @request.headers[ApiEngineBase::ApplicationController::AUTHENTICATION_HEADER] = nil
16
17
  end
17
18
  end
18
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ApiEngineBase
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -1,10 +1,10 @@
1
+ require "api_engine_base/error"
2
+
1
3
  require "api_engine_base/version"
2
4
  require "api_engine_base/engine"
3
5
  require "api_engine_base/configuration/config"
4
6
 
5
7
  module ApiEngineBase
6
- class Error < StandardError; end
7
-
8
8
  def self.config
9
9
  @config ||= Configuration::Config.new
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_engine_base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - matt-taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-02 00:00:00.000000000 Z
11
+ date: 2025-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rotp
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '0.10'
103
+ version: '0.11'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '0.10'
110
+ version: '0.11'
111
111
  description: ApiEngineBase is the Base API to handle all the things you don't want
112
112
  to for a Rails API only backend serving a Dedicated frontend
113
113
  email:
@@ -119,8 +119,10 @@ files:
119
119
  - MIT-LICENSE
120
120
  - README.md
121
121
  - Rakefile
122
+ - app/controllers/api_engine_base/admin_controller.rb
122
123
  - app/controllers/api_engine_base/application_controller.rb
123
124
  - app/controllers/api_engine_base/auth/plain_text_controller.rb
125
+ - app/controllers/api_engine_base/user_controller.rb
124
126
  - app/controllers/api_engine_base/username_controller.rb
125
127
  - app/controllers/concerns/api_engine_base/schematizable.rb
126
128
  - app/helpers/api_engine_base/application_helper.rb
@@ -131,9 +133,12 @@ files:
131
133
  - app/models/api_engine_base/application_record.rb
132
134
  - app/models/user.rb
133
135
  - app/models/user_secret.rb
136
+ - app/services/api_engine_base/README.md
134
137
  - app/services/api_engine_base/argument_validation.rb
138
+ - app/services/api_engine_base/argument_validation/README.md
135
139
  - app/services/api_engine_base/argument_validation/class_methods.rb
136
140
  - app/services/api_engine_base/argument_validation/instance_methods.rb
141
+ - app/services/api_engine_base/authorize/validate.rb
137
142
  - app/services/api_engine_base/jwt/authenticate_user.rb
138
143
  - app/services/api_engine_base/jwt/decode.rb
139
144
  - app/services/api_engine_base/jwt/encode.rb
@@ -151,13 +156,21 @@ files:
151
156
  - app/services/api_engine_base/secrets/verify.rb
152
157
  - app/services/api_engine_base/service_base.rb
153
158
  - app/services/api_engine_base/service_logging.rb
159
+ - app/services/api_engine_base/user_attributes/modify.rb
160
+ - app/services/api_engine_base/user_attributes/roles.rb
154
161
  - app/services/api_engine_base/username/available.rb
155
162
  - app/views/api_engine_base/email_verification_mailer/verify_email.html.erb
156
163
  - config/routes.rb
157
164
  - db/migrate/20241117043720_create_api_engine_base_users.rb
158
165
  - db/migrate/20241204065708_create_api_engine_base_user_secrets.rb
159
166
  - lib/api_engine_base.rb
167
+ - lib/api_engine_base/authorization.rb
168
+ - lib/api_engine_base/authorization/default.yml
169
+ - lib/api_engine_base/authorization/entity.rb
170
+ - lib/api_engine_base/authorization/role.rb
171
+ - lib/api_engine_base/configuration/admin/config.rb
160
172
  - lib/api_engine_base/configuration/application/config.rb
173
+ - lib/api_engine_base/configuration/authorization/config.rb
161
174
  - lib/api_engine_base/configuration/base.rb
162
175
  - lib/api_engine_base/configuration/config.rb
163
176
  - lib/api_engine_base/configuration/email/config.rb
@@ -167,13 +180,17 @@ files:
167
180
  - lib/api_engine_base/configuration/login/strategy/plain_text/email_verify.rb
168
181
  - lib/api_engine_base/configuration/login/strategy/plain_text/lockable.rb
169
182
  - lib/api_engine_base/configuration/otp/config.rb
183
+ - lib/api_engine_base/configuration/user/config.rb
170
184
  - lib/api_engine_base/configuration/username/check.rb
171
185
  - lib/api_engine_base/configuration/username/config.rb
172
186
  - lib/api_engine_base/engine.rb
187
+ - lib/api_engine_base/error.rb
173
188
  - lib/api_engine_base/schema.rb
189
+ - lib/api_engine_base/schema/admin/users.rb
174
190
  - lib/api_engine_base/schema/error/base.rb
175
191
  - lib/api_engine_base/schema/error/invalid_argument.rb
176
192
  - lib/api_engine_base/schema/error/invalid_argument_response.rb
193
+ - lib/api_engine_base/schema/page.rb
177
194
  - lib/api_engine_base/schema/plain_text/create_user_request.rb
178
195
  - lib/api_engine_base/schema/plain_text/create_user_response.rb
179
196
  - lib/api_engine_base/schema/plain_text/email_verify_request.rb
@@ -182,6 +199,7 @@ files:
182
199
  - lib/api_engine_base/schema/plain_text/email_verify_send_response.rb
183
200
  - lib/api_engine_base/schema/plain_text/login_request.rb
184
201
  - lib/api_engine_base/schema/plain_text/login_response.rb
202
+ - lib/api_engine_base/schema/user.rb
185
203
  - lib/api_engine_base/spec_helper.rb
186
204
  - lib/api_engine_base/version.rb
187
205
  - lib/generators/api_engine_base/configure/USAGE