command_tower 0.3.0

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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +59 -0
  4. data/Rakefile +32 -0
  5. data/app/controllers/command_tower/admin_controller.rb +104 -0
  6. data/app/controllers/command_tower/application_controller.rb +81 -0
  7. data/app/controllers/command_tower/auth/plain_text_controller.rb +132 -0
  8. data/app/controllers/command_tower/inbox/message_blast_controller.rb +89 -0
  9. data/app/controllers/command_tower/inbox/message_controller.rb +79 -0
  10. data/app/controllers/command_tower/user_controller.rb +49 -0
  11. data/app/controllers/command_tower/username_controller.rb +26 -0
  12. data/app/helpers/command_tower/application_helper.rb +4 -0
  13. data/app/helpers/command_tower/schema_helper.rb +29 -0
  14. data/app/jobs/command_tower/application_job.rb +4 -0
  15. data/app/mailers/command_tower/application_mailer.rb +8 -0
  16. data/app/mailers/command_tower/email_verification_mailer.rb +12 -0
  17. data/app/models/command_tower/application_record.rb +45 -0
  18. data/app/models/message.rb +30 -0
  19. data/app/models/message_blast.rb +27 -0
  20. data/app/models/user.rb +61 -0
  21. data/app/models/user_secret.rb +72 -0
  22. data/app/services/command_tower/README.md +49 -0
  23. data/app/services/command_tower/argument_validation/README.md +192 -0
  24. data/app/services/command_tower/argument_validation/class_methods.rb +178 -0
  25. data/app/services/command_tower/argument_validation/instance_methods.rb +148 -0
  26. data/app/services/command_tower/argument_validation.rb +11 -0
  27. data/app/services/command_tower/authorize/validate.rb +49 -0
  28. data/app/services/command_tower/inbox_service/blast/delete.rb +23 -0
  29. data/app/services/command_tower/inbox_service/blast/metadata.rb +26 -0
  30. data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +24 -0
  31. data/app/services/command_tower/inbox_service/blast/retrieve.rb +30 -0
  32. data/app/services/command_tower/inbox_service/blast/upsert.rb +67 -0
  33. data/app/services/command_tower/inbox_service/message/metadata.rb +35 -0
  34. data/app/services/command_tower/inbox_service/message/modify.rb +44 -0
  35. data/app/services/command_tower/inbox_service/message/retrieve.rb +36 -0
  36. data/app/services/command_tower/inbox_service/message/send.rb +33 -0
  37. data/app/services/command_tower/jwt/authenticate_user.rb +86 -0
  38. data/app/services/command_tower/jwt/decode.rb +21 -0
  39. data/app/services/command_tower/jwt/encode.rb +15 -0
  40. data/app/services/command_tower/jwt/login_create.rb +21 -0
  41. data/app/services/command_tower/jwt/time_delay_token.rb +17 -0
  42. data/app/services/command_tower/login_strategy/plain_text/create.rb +43 -0
  43. data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +29 -0
  44. data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +20 -0
  45. data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +23 -0
  46. data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +24 -0
  47. data/app/services/command_tower/login_strategy/plain_text/login.rb +50 -0
  48. data/app/services/command_tower/secrets/cleanse.rb +14 -0
  49. data/app/services/command_tower/secrets/generate.rb +62 -0
  50. data/app/services/command_tower/secrets/verify.rb +27 -0
  51. data/app/services/command_tower/secrets.rb +15 -0
  52. data/app/services/command_tower/service_base.rb +89 -0
  53. data/app/services/command_tower/service_logging.rb +41 -0
  54. data/app/services/command_tower/user_attributes/modify.rb +68 -0
  55. data/app/services/command_tower/user_attributes/roles.rb +27 -0
  56. data/app/services/command_tower/username/available.rb +64 -0
  57. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +26 -0
  58. data/config/routes.rb +55 -0
  59. data/db/migrate/20241117043720_create_command_tower_users.rb +42 -0
  60. data/db/migrate/20241204065708_create_command_tower_user_secrets.rb +16 -0
  61. data/db/migrate/20250223023306_create_command_tower_messages.rb +12 -0
  62. data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +14 -0
  63. data/lib/command_tower/authorization/default.yml +42 -0
  64. data/lib/command_tower/authorization/entity.rb +101 -0
  65. data/lib/command_tower/authorization/role.rb +101 -0
  66. data/lib/command_tower/authorization.rb +85 -0
  67. data/lib/command_tower/configuration/admin/config.rb +18 -0
  68. data/lib/command_tower/configuration/application/config.rb +40 -0
  69. data/lib/command_tower/configuration/authorization/config.rb +24 -0
  70. data/lib/command_tower/configuration/base.rb +11 -0
  71. data/lib/command_tower/configuration/config.rb +77 -0
  72. data/lib/command_tower/configuration/email/config.rb +87 -0
  73. data/lib/command_tower/configuration/jwt/config.rb +22 -0
  74. data/lib/command_tower/configuration/login/config.rb +18 -0
  75. data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +57 -0
  76. data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +50 -0
  77. data/lib/command_tower/configuration/login/strategy/plain_text/lockable.rb +27 -0
  78. data/lib/command_tower/configuration/otp/config.rb +54 -0
  79. data/lib/command_tower/configuration/user/config.rb +56 -0
  80. data/lib/command_tower/configuration/username/check.rb +31 -0
  81. data/lib/command_tower/configuration/username/config.rb +41 -0
  82. data/lib/command_tower/engine.rb +53 -0
  83. data/lib/command_tower/error.rb +5 -0
  84. data/lib/command_tower/schema/admin/users.rb +15 -0
  85. data/lib/command_tower/schema/error/base.rb +15 -0
  86. data/lib/command_tower/schema/error/invalid_argument.rb +15 -0
  87. data/lib/command_tower/schema/error/invalid_argument_response.rb +17 -0
  88. data/lib/command_tower/schema/inbox/blast_request.rb +15 -0
  89. data/lib/command_tower/schema/inbox/blast_response.rb +16 -0
  90. data/lib/command_tower/schema/inbox/message_blast_entity.rb +16 -0
  91. data/lib/command_tower/schema/inbox/message_blast_metadata.rb +16 -0
  92. data/lib/command_tower/schema/inbox/message_entity.rb +14 -0
  93. data/lib/command_tower/schema/inbox/metadata.rb +18 -0
  94. data/lib/command_tower/schema/inbox/modified.rb +13 -0
  95. data/lib/command_tower/schema/page.rb +14 -0
  96. data/lib/command_tower/schema/plain_text/create_user_request.rb +18 -0
  97. data/lib/command_tower/schema/plain_text/create_user_response.rb +17 -0
  98. data/lib/command_tower/schema/plain_text/email_verify_request.rb +11 -0
  99. data/lib/command_tower/schema/plain_text/email_verify_response.rb +11 -0
  100. data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +9 -0
  101. data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +11 -0
  102. data/lib/command_tower/schema/plain_text/login_request.rb +15 -0
  103. data/lib/command_tower/schema/plain_text/login_response.rb +13 -0
  104. data/lib/command_tower/schema/user.rb +28 -0
  105. data/lib/command_tower/schema.rb +38 -0
  106. data/lib/command_tower/spec_helper.rb +19 -0
  107. data/lib/command_tower/version.rb +5 -0
  108. data/lib/command_tower.rb +33 -0
  109. data/lib/generators/api_engine_base/configure/USAGE +8 -0
  110. data/lib/generators/api_engine_base/configure/configure_generator.rb +12 -0
  111. data/lib/tasks/auto_annotate_models.rake +60 -0
  112. metadata +255 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cf20c74b952fc6ca7dc2c7a67212ce9e5e8eb96a93bcb6173bd40564d28ceecc
4
+ data.tar.gz: 1e6d03692209feecdad59b05f8296792ab5ccc0b62f301dc80bc5d88afe4a091
5
+ SHA512:
6
+ metadata.gz: a6aeb3aa6c47f3b253b26bc0778c8862e80b78601bd495acea69709a4b0f39f830d3b236c1ed3385b0ad8457598dde34203a200ff809aa86e839c02706c10abd
7
+ data.tar.gz: a3d9687e594904270b83b2c033cb1c83abe38c9ebceeef3b4c8c3b482e95b86b5423cb05f5d6598aa3659f1cca7d3996514a39d9fdbe4b67f975e2910f996b60
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # CommandTower
2
+ This is an API only base engine to build on top of. This Engine takes care of all Authentication, Token Refresh, and RBAC Roles so that you do not have to! For all applications, you can get right to work on implementing the code directly related to your project rather than dealing with the administrative overhead.
3
+
4
+ While this gem is heavily opinionated, everything can be configured to your liking.
5
+
6
+ ## Installation
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "command_tower"
11
+ ```
12
+
13
+ And then execute:
14
+ ```bash
15
+ $ bundle
16
+ ```
17
+
18
+ Or install it yourself as:
19
+ ```bash
20
+ $ gem install command_tower
21
+ ```
22
+
23
+ ## Initializing CommandTower
24
+ Please follow all steps in [Initializing CommandTower](docs/initializing.md)
25
+
26
+
27
+ ## Available Routes
28
+
29
+ For more info, check out [Controllers ReadMe](docs/controllers.md)
30
+
31
+ Additionally, You can check out [RSpec Integration Testing](/spec/integration_test)
32
+
33
+ ## Available Models
34
+
35
+ CommandTower provides several Models at the in the root namespace. Core Models like `User` and `UserSecret` are readily available. Don't forget! You can add additional methods to these classes by opening them back up.
36
+
37
+ For more info, check out [Models ReadMe](doc/models.md)
38
+
39
+ ## Authentication (JWT BearerToken)
40
+ Authentication ensures that we know which user is requesting the action. When the Engine is unable to authenticate, a `401` status code is returned.
41
+
42
+ For more info, check out [Authentication ReadMe](docs/authentication.md)
43
+
44
+ ## Authorization (RBAC)
45
+ Authorization is only done after authentication. This is the act of ensuring that the user can perform the action it is requesting. Put differently, I know who you are, but I need to validate you have permissions to complete the action. When the engine is unable to authorize the user, a `403` status code is returned.
46
+
47
+ For more info, check out [Authentication ReadMe](docs/authorization.md)
48
+
49
+ ## Sensitive Changes
50
+
51
+ For more info, check out [Sensitive Routes](docs/sensitive_routes.md)
52
+
53
+ ## ServiceBase
54
+ ServiceBase is built on top of Interactor. The ServiceBase is the heart of all logic for CommandTower. It includes Logging and enhanced ArgumentValidation that can directly return back to the API request.
55
+
56
+ For more info, check out [ServiceBase ReadMe](app/services/command_tower/README.md)
57
+
58
+ ## License
59
+ The engine is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
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 = 'CommandTower'
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("rails_app/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ class AdminController < ::CommandTower::ApplicationController
5
+ include CommandTower::SchemaHelper
6
+
7
+ before_action :authenticate_user!
8
+ before_action :authorize_user!
9
+ before_action :user!, only: [:modify, :modify_role]
10
+
11
+ # Pagination is needed here
12
+ def show
13
+ schemafied_users = User.all.map { CommandTower::Schema::User.convert_user_object(user: _1) }
14
+ schema = CommandTower::Schema::Admin::Users.new(users: schemafied_users)
15
+ schema_succesful!(status: 200, schema:)
16
+ end
17
+
18
+ def modify
19
+ result = CommandTower::UserAttributes::Modify.(user:, admin_user:, **modify_params)
20
+ if result.success?
21
+ schema = CommandTower::Schema::User.convert_user_object(user: user.reload)
22
+ status = 201
23
+ schema_succesful!(status:, schema:)
24
+ else
25
+ if result.invalid_arguments
26
+ invalid_arguments!(
27
+ status: 400,
28
+ message: result.msg,
29
+ argument_object: result.invalid_argument_hash,
30
+ schema: CommandTower::Schema::PlainText::LoginRequest
31
+ )
32
+ else
33
+ server_error!(result:)
34
+ end
35
+ end
36
+ end
37
+
38
+ def modify_role
39
+ result = CommandTower::UserAttributes::Roles.(user:, admin_user:, roles: params[:roles] || [])
40
+ if result.success?
41
+ schema = CommandTower::Schema::User.convert_user_object(user: user.reload)
42
+ status = 201
43
+ schema_succesful!(status:, schema:)
44
+ else
45
+ if result.invalid_arguments
46
+ invalid_arguments!(
47
+ status: 400,
48
+ message: result.msg,
49
+ argument_object: result.invalid_argument_hash,
50
+ schema: CommandTower::Schema::PlainText::LoginRequest
51
+ )
52
+ else
53
+ server_error!(result:)
54
+ end
55
+ end
56
+ end
57
+
58
+ def impersonate
59
+ # TODO: @matt-taylor
60
+ end
61
+
62
+ private
63
+
64
+ def server_error!(result:)
65
+ status = 500
66
+ schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
67
+ render(json: schema.to_h, status:)
68
+ end
69
+
70
+ def modify_params
71
+ {
72
+ email: params[:email],
73
+ email_validated: safe_boolean(value: params[:email_validated]),
74
+ first_name: params[:first_name],
75
+ last_name: params[:last_name],
76
+ username: params[:username],
77
+ verifier_token: safe_boolean(value: params[:verifier_token]),
78
+ }.compact
79
+ end
80
+
81
+ def admin_user
82
+ # current_user is defined via authenticate_user! before action
83
+ current_user
84
+ end
85
+
86
+ def user!
87
+ _user = User.where(id: params[:user_id]).first
88
+ if _user
89
+ @user = _user
90
+ return true
91
+ end
92
+
93
+ status = 400
94
+ schema = CommandTower::Schema::Error::Base.new(status:, message: "Invalid user")
95
+ render(json: schema.to_h, status:)
96
+ # Must return false so callbacks know to halt propagation
97
+ false
98
+ end
99
+
100
+ def user
101
+ @user ||= nil
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ class ApplicationController < ActionController::API
5
+ AUTHENTICATION_HEADER = "Authentication"
6
+ AUTHENTICATION_EXPIRE_HEADER = "X-Authentication-Expire"
7
+ AUTHENTICATION_WITH_RESET = "X-Authentication-Reset"
8
+
9
+ def safe_boolean(value:)
10
+ return nil unless [true, false, "true", "false", "0", "1", 0, 1].include?(value)
11
+
12
+ ActiveModel::Type::Boolean.new.cast(value)
13
+ end
14
+
15
+ ###
16
+ # Authenticate user via the passed in header
17
+ # AUTHENTICATION_HEADER="Bearer: {token value}"
18
+ def authenticate_user!(bypass_email_validation: false)
19
+ raw_token = request.headers[AUTHENTICATION_HEADER]
20
+ if raw_token.nil?
21
+ status = 401
22
+ schema = CommandTower::Schema::Error::Base.new(status:, message: "Bearer token missing")
23
+ render(json: schema.to_h, status:)
24
+ return false
25
+ end
26
+
27
+ token = raw_token.split("Bearer:")[1].strip
28
+ with_reset = safe_boolean(value: request.headers[AUTHENTICATION_WITH_RESET])
29
+ result = CommandTower::Jwt::AuthenticateUser.(token:, bypass_email_validation:, with_reset:)
30
+ if result.success?
31
+ @current_user = result.user
32
+ response.set_header(AUTHENTICATION_EXPIRE_HEADER, result.expires_at)
33
+ if with_reset
34
+ response.set_header(AUTHENTICATION_WITH_RESET, result.generated_token)
35
+ end
36
+ true
37
+ else
38
+ status = 401
39
+ schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
40
+ render(json: schema.to_h, status:)
41
+ # Must return false so callbacks know to halt propagation
42
+ false
43
+ end
44
+ end
45
+
46
+ ###
47
+ # Authenticate user via the passed in header without validating email
48
+ def authenticate_user_without_email_verification!
49
+ authenticate_user!(bypass_email_validation: true)
50
+ end
51
+
52
+ ###
53
+ # After Authenticating user, see if the user needs authorization on the route
54
+ def authorize_user!
55
+ if current_user.nil?
56
+ Rails.logger.error { "Current User is not defined. This means that authenticate_user! was not called" }
57
+ status = 401
58
+ schema = CommandTower::Schema::Error::Base.new(status:, message: "Bearer token missing")
59
+ render(json: schema.to_h, status:)
60
+ return false
61
+ end
62
+ result = CommandTower::Authorize::Validate.(user: current_user, controller: self.class, method: params[:action])
63
+
64
+ if result.success?
65
+ @current_user = result.user
66
+ true
67
+ else
68
+ # Current user is not authorized for the current Controller#action
69
+ status = 403
70
+ schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
71
+ render(json: schema.to_h, status:)
72
+ # Must return false so callbacks know to halt propagation
73
+ false
74
+ end
75
+ end
76
+
77
+ def current_user
78
+ @current_user ||= nil
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,132 @@
1
+ module CommandTower
2
+ module Auth
3
+ class PlainTextController < ::CommandTower::ApplicationController
4
+ include CommandTower::SchemaHelper
5
+
6
+ before_action :authenticate_user_without_email_verification!, only: [:email_verify_post, :email_verify_resend_post]
7
+
8
+ # POST /auth/login
9
+ # Login to the application and create/set the JWT token
10
+ def login_post
11
+ result = CommandTower::LoginStrategy::PlainText::Login.(**login_params)
12
+ if result.success?
13
+ schema = CommandTower::Schema::PlainText::LoginResponse.new(
14
+ token: result.token,
15
+ header_name: AUTHENTICATION_HEADER,
16
+ message: "Successfully logged user in"
17
+ )
18
+ status = 201
19
+ schema_succesful!(status:, schema:)
20
+ else
21
+ if result.invalid_arguments
22
+ invalid_arguments!(
23
+ status: 401,
24
+ message: result.msg,
25
+ argument_object: result.invalid_argument_hash,
26
+ schema: CommandTower::Schema::PlainText::LoginRequest
27
+ )
28
+ else
29
+ json_result = { msg: result.msg }
30
+ status = 400
31
+ render(json: schema.to_h, status:)
32
+ end
33
+ end
34
+ end
35
+
36
+ # POST /auth/create
37
+ # New PlainText user creation
38
+ def create_post
39
+ result = CommandTower::LoginStrategy::PlainText::Create.(**create_params)
40
+ if result.success?
41
+ schema = CommandTower::Schema::PlainText::CreateUserResponse.new(
42
+ full_name: result.user.full_name,
43
+ first_name: result.first_name,
44
+ last_name: result.last_name,
45
+ username: result.username,
46
+ email: result.email,
47
+ msg: "Successfully created new User",
48
+ )
49
+ status = 201
50
+ schema_succesful!(status:, schema:)
51
+ else
52
+ if result.invalid_arguments
53
+ invalid_arguments!(
54
+ status: 400,
55
+ message: result.msg,
56
+ argument_object: result.invalid_argument_hash,
57
+ schema: CommandTower::Schema::PlainText::CreateUserRequest
58
+ )
59
+ end
60
+ end
61
+ end
62
+
63
+ # POST /auth/email/verify
64
+ # Verifies a logged in users email verification code when enabled
65
+ def email_verify_post
66
+ if current_user.email_validated
67
+ schema = CommandTower::Schema::PlainText::EmailVerifyResponse.new(message: "Email is already verified.")
68
+ status = 200
69
+ schema_succesful!(status:, schema:)
70
+ else
71
+ result = CommandTower::LoginStrategy::PlainText::EmailVerification::Verify.(user: current_user, code: params[:code])
72
+ if result.success?
73
+ schema = CommandTower::Schema::PlainText::EmailVerifyResponse.new(message: "Successfully verified email")
74
+ status = 201
75
+ schema_succesful!(status:, schema:)
76
+ else
77
+ if result.invalid_arguments
78
+ invalid_arguments!(
79
+ status: result.status || 403,
80
+ message: result.msg,
81
+ argument_object: result.invalid_argument_hash,
82
+ schema: CommandTower::Schema::PlainText::EmailVerifyRequest
83
+ )
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ # POST /auth/email/send
90
+ # Sends a logged in users email verification code
91
+ def email_verify_resend_post
92
+ if current_user.email_validated
93
+ schema = CommandTower::Schema::PlainText::EmailVerifyResponse.new(message: "Email is already verified. No code required")
94
+ status = 200
95
+ schema_succesful!(status:, schema:)
96
+ else
97
+ result = CommandTower::LoginStrategy::PlainText::EmailVerification::Send.(user: current_user)
98
+ if result.success?
99
+ schema = CommandTower::Schema::PlainText::EmailVerifyResponse.new(message: "Successfully sent Email verification code")
100
+ status = 201
101
+ schema_succesful!(status:, schema:)
102
+ else
103
+ schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
104
+ status = result.status || 401
105
+ render(json: schema.to_h, status:)
106
+ end
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def login_params
113
+ {
114
+ username: params[:username],
115
+ email: params[:email],
116
+ password: params[:password],
117
+ }
118
+ end
119
+
120
+ def create_params
121
+ {
122
+ first_name: params[:first_name],
123
+ last_name: params[:last_name],
124
+ username: params[:username],
125
+ email: params[:email],
126
+ password: params[:password],
127
+ password_confirmation: params[:password_confirmation],
128
+ }
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ module Inbox
5
+ class MessageBlastController < ::CommandTower::ApplicationController
6
+ include CommandTower::SchemaHelper
7
+
8
+ before_action :authenticate_user!
9
+ before_action :authorize_user!
10
+
11
+ # GET /inbox/blast
12
+ def metadata
13
+ result = CommandTower::InboxService::Blast::Metadata.(id: params[:id].to_i)
14
+ schema_succesful!(status: 200, schema: result.metadata)
15
+ end
16
+
17
+ # GET /inbox/blast/:id
18
+ def blast
19
+ result = CommandTower::InboxService::Blast::Retrieve.(id: params[:id].to_i)
20
+ if result.success?
21
+ schema = result.message_blast
22
+ status = 200
23
+ schema_succesful!(status:, schema:)
24
+ else
25
+ invalid_arguments!(
26
+ status: 400,
27
+ message: result.msg,
28
+ argument_object: result.invalid_argument_hash,
29
+ schema: CommandTower::Schema::PlainText::LoginRequest,
30
+ )
31
+ end
32
+ end
33
+
34
+ # POST /inbox/blast
35
+ def create
36
+ upsert
37
+ end
38
+
39
+ # PATCH /inbox/blast/:id
40
+ def modify
41
+ upsert(id: params[:id].to_i)
42
+ end
43
+
44
+ # DELETE /inbox/blast/:id
45
+ def delete
46
+ result = CommandTower::InboxService::Blast::Delete.(id: params[:id].to_i)
47
+ if result.success?
48
+ schema = result.message
49
+ status = 200
50
+ render :json, { id: params[:id], msg: "Message Blast message deleted" }
51
+ else
52
+ invalid_arguments!(
53
+ status: 400,
54
+ message: result.msg,
55
+ argument_object: result.invalid_argument_hash,
56
+ schema: CommandTower::Schema::PlainText::LoginRequest,
57
+ )
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def upsert(id: nil)
64
+ upsert_params = {
65
+ user: current_user,
66
+ existing_users: safe_boolean(value: params[:existing_users]),
67
+ new_users: safe_boolean(value: params[:new_users]),
68
+ text: params[:text],
69
+ title: params[:title],
70
+ id:,
71
+ }.compact
72
+ result = CommandTower::InboxService::Blast::Upsert.(**upsert_params)
73
+
74
+ if result.success?
75
+ schema = result.blast
76
+ status = 200
77
+ schema_succesful!(status:, schema:)
78
+ else
79
+ invalid_arguments!(
80
+ status: 400,
81
+ message: result.msg,
82
+ argument_object: result.invalid_argument_hash,
83
+ schema: CommandTower::Schema::Inbox::BlastRequest
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ module Inbox
5
+ class MessageController < ::CommandTower::ApplicationController
6
+ include CommandTower::SchemaHelper
7
+
8
+ before_action :authenticate_user!
9
+
10
+ # GET: /inbox/messages
11
+ def metadata
12
+ result = CommandTower::InboxService::Message::Metadata.(user: current_user)
13
+ if result.success?
14
+ schema = result.metadata
15
+ status = 200
16
+ schema_succesful!(status:, schema:)
17
+ else
18
+ invalid_arguments!(
19
+ status: 400,
20
+ message: result.msg,
21
+ argument_object: result.invalid_argument_hash,
22
+ schema: CommandTower::Schema::PlainText::LoginRequest
23
+ )
24
+ end
25
+ end
26
+
27
+ # GET: /inbox/messages/:id
28
+ def message
29
+ result = CommandTower::InboxService::Message::Retrieve.(user: current_user, id: params[:id].to_i)
30
+ if result.success?
31
+ schema = result.message
32
+ status = 200
33
+ schema_succesful!(status:, schema:)
34
+ else
35
+ invalid_arguments!(
36
+ status: 400,
37
+ message: result.msg,
38
+ argument_object: result.invalid_argument_hash,
39
+ schema: CommandTower::Schema::PlainText::LoginRequest
40
+ )
41
+ end
42
+ end
43
+
44
+ # POST: /inbox/messages/ack
45
+ # Body { ids: [<list of ids to ack>] }
46
+ def ack
47
+ modify(type: CommandTower::InboxService::Message::Modify::VIEWED)
48
+ end
49
+
50
+ # POST: /inbox/messages/delete
51
+ # Body { ids: [<list of ids to delete>] }
52
+ def delete
53
+ modify(type: CommandTower::InboxService::Message::Modify::DELETE)
54
+ end
55
+
56
+ private
57
+
58
+ def modify(type:)
59
+ result = CommandTower::InboxService::Message::Modify.(
60
+ user: current_user,
61
+ ids: params[:ids],
62
+ type:,
63
+ )
64
+ if result.success?
65
+ schema = result.modified
66
+ status = 200
67
+ schema_succesful!(status:, schema:)
68
+ else
69
+ invalid_arguments!(
70
+ status: 400,
71
+ message: result.msg,
72
+ argument_object: result.invalid_argument_hash,
73
+ schema: CommandTower::Schema::PlainText::LoginRequest
74
+ )
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ class UserController < ::CommandTower::ApplicationController
5
+ include CommandTower::SchemaHelper
6
+
7
+ before_action :authenticate_user!
8
+
9
+ def show
10
+ schema = CommandTower::Schema::User.convert_user_object(user: current_user)
11
+ schema_succesful!(status: 200, schema:)
12
+ end
13
+
14
+ def modify
15
+ result = CommandTower::UserAttributes::Modify.(user: current_user, **modify_params)
16
+ if result.success?
17
+ schema = CommandTower::Schema::User.convert_user_object(user: current_user.reload)
18
+ status = 201
19
+ schema_succesful!(status:, schema:)
20
+ else
21
+ if result.invalid_arguments
22
+ invalid_arguments!(
23
+ status: 400,
24
+ message: result.msg,
25
+ argument_object: result.invalid_argument_hash,
26
+ schema: CommandTower::Schema::PlainText::LoginRequest
27
+ )
28
+ else
29
+ status = 500
30
+ schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
31
+ render(json: schema.to_h, status:)
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def modify_params
39
+ {
40
+ email: params[:email],
41
+ email_validated: safe_boolean(value: params[:email_validated]),
42
+ first_name: params[:first_name],
43
+ last_name: params[:last_name],
44
+ username: params[:username],
45
+ verifier_token: safe_boolean(value: params[:verifier_token]),
46
+ }.compact
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,26 @@
1
+ module CommandTower
2
+ class UsernameController < ::CommandTower::ApplicationController
3
+
4
+ # GET /username/available/:username
5
+ def username_availability
6
+ result = CommandTower::Username::Available.(username: params[:username])
7
+
8
+ if result.success?
9
+ json_result = {
10
+ username: {
11
+ available: result.available,
12
+ valid: result.valid,
13
+ description: CommandTower.config.username.username_failure_message
14
+ }
15
+ }
16
+ status = 200
17
+ else
18
+ json_result = { msg: result.msg }
19
+ json_result[:invalid_arguments] = true if result.invalid_arguments
20
+ status = 401
21
+ end
22
+
23
+ render json: json_result, status: status
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ module CommandTower
2
+ module ApplicationHelper
3
+ end
4
+ end