diff --git a/app/contracts/application_contract.rb b/app/contracts/application_contract.rb index f80b163..1490cf6 100644 --- a/app/contracts/application_contract.rb +++ b/app/contracts/application_contract.rb @@ -3,6 +3,8 @@ require 'dry-validation' class ApplicationContract < Dry::Validation::Contract + include Supports::ApplicationContract::SwaggerInput + config.messages.backend = :i18n register_macro(:password_confirmation) do diff --git a/app/contracts/users/passwords/send_instructions_contract.rb b/app/contracts/users/passwords/send_instructions_contract.rb index c59ba72..6acddfd 100644 --- a/app/contracts/users/passwords/send_instructions_contract.rb +++ b/app/contracts/users/passwords/send_instructions_contract.rb @@ -5,6 +5,8 @@ module Passwords class SendInstructionsContract < ApplicationContract params do required(:email).filled(Types::Email) + required(:client_id).filled(:string) + required(:client_secret).filled(:string) end end end diff --git a/app/contracts/users/passwords/update_contract.rb b/app/contracts/users/passwords/update_contract.rb index 8dfbf55..67800b1 100644 --- a/app/contracts/users/passwords/update_contract.rb +++ b/app/contracts/users/passwords/update_contract.rb @@ -7,6 +7,8 @@ class UpdateContract < ApplicationContract required(:reset_password_token).filled(:string) required(:password) { filled? & str? & min_size?(Devise.password_length.min) } required(:password_confirmation) { filled? & str? & min_size?(Devise.password_length.min) } + required(:client_id).filled(:string) + required(:client_secret).filled(:string) end rule(:password).validate(:password_confirmation) diff --git a/app/contracts/users/registrations/register_contract.rb b/app/contracts/users/registrations/register_contract.rb index 03269e3..bfc1f65 100644 --- a/app/contracts/users/registrations/register_contract.rb +++ b/app/contracts/users/registrations/register_contract.rb @@ -6,6 +6,8 @@ class RegisterContract < ApplicationContract params do required(:email).filled(Types::Email) required(:password).filled(:str?, min_size?: Devise.password_length.min) + required(:client_id).filled(:string) + required(:client_secret).filled(:string) end end end diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb index 8bed593..bfbf629 100644 --- a/app/controllers/users/passwords_controller.rb +++ b/app/controllers/users/passwords_controller.rb @@ -27,7 +27,7 @@ def update private def password_params - params.permit(:email, :reset_password_token, :password, :password_confirmation) + params.permit(:email, :reset_password_token, :password, :password_confirmation, :client_id, :client_secret) end end end diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 55d1441..2992bc6 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -18,7 +18,7 @@ def create private def registration_params - params.permit(:email, :password) + params.permit(:email, :password, :client_id, :client_secret) end end end diff --git a/app/services/users_service/registrations/register.rb b/app/services/users_service/registrations/register.rb index 95cbede..da0d66b 100644 --- a/app/services/users_service/registrations/register.rb +++ b/app/services/users_service/registrations/register.rb @@ -21,7 +21,9 @@ def call private def create_user - UsersService::Create.new(params:).call + allowed_params = params.except(:client_id, :client_secret) + + UsersService::Create.new(params: allowed_params).call end def create_access_token(user) diff --git a/app/swagger_docs/controllers/users/passwords_controller.rb b/app/swagger_docs/controllers/users/passwords_controller.rb index 244003d..afe4fd5 100644 --- a/app/swagger_docs/controllers/users/passwords_controller.rb +++ b/app/swagger_docs/controllers/users/passwords_controller.rb @@ -19,7 +19,7 @@ class PasswordsController key :required, true content :'application/json' do schema do - key :'$ref', :UserResetPasswordInput + key :'$ref', :UsersPasswordsSendInstructionsContractInput end end end @@ -65,7 +65,7 @@ class PasswordsController key :required, true content :'application/json' do schema do - key :'$ref', :UserUpdatePasswordInput + key :'$ref', :UsersPasswordsUpdateContractInput end end end diff --git a/app/swagger_docs/controllers/users/registrations_controller.rb b/app/swagger_docs/controllers/users/registrations_controller.rb index 7d94737..46b2102 100644 --- a/app/swagger_docs/controllers/users/registrations_controller.rb +++ b/app/swagger_docs/controllers/users/registrations_controller.rb @@ -19,7 +19,7 @@ class RegistrationsController key :required, true content :'application/json' do schema do - key :'$ref', :UserSignUpInput + key :'$ref', :UsersRegistrationsRegisterContractInput end end end diff --git a/app/swagger_docs/inputs/user/reset_password_input.rb b/app/swagger_docs/inputs/user/reset_password_input.rb deleted file mode 100644 index 19d605b..0000000 --- a/app/swagger_docs/inputs/user/reset_password_input.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Inputs - module User - class ResetPasswordInput - include Swagger::Blocks - - swagger_component do - schema :UserResetPasswordInput do - key :required, %i[email client_id client_secret] - - property :email do - key :type, :string - key :example, 'test@test.com' - end - - property :client_id do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - - property :client_secret do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - end - end - end - end -end diff --git a/app/swagger_docs/inputs/user/sign_up_input.rb b/app/swagger_docs/inputs/user/sign_up_input.rb deleted file mode 100644 index 2df84a2..0000000 --- a/app/swagger_docs/inputs/user/sign_up_input.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Inputs - module User - class SignUpInput - include Swagger::Blocks - - swagger_component do - schema :UserSignUpInput do - key :required, %i[email password client_id client_secret] - - property :email do - key :type, :string - key :example, 'test@test.com' - end - - property :password do - key :type, :string - key :example, 'password' - end - - property :client_id do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - - property :client_secret do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - end - end - end - end -end diff --git a/app/swagger_docs/inputs/user/update_password_input.rb b/app/swagger_docs/inputs/user/update_password_input.rb deleted file mode 100644 index f2044c7..0000000 --- a/app/swagger_docs/inputs/user/update_password_input.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -module Inputs - module User - class UpdatePasswordInput - include Swagger::Blocks - - swagger_component do - schema :UserUpdatePasswordInput do - key :required, %i[reset_password_token password password_confirmation client_id client_secret] - - property :reset_password_token do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - - property :password do - key :type, :string - key :example, 'newpassword' - end - - property :password_confirmation do - key :type, :string - key :example, 'newpassword' - end - - property :client_id do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - - property :client_secret do - key :type, :string - key :example, 'e7c8f8f0-e8e0-4b0f-b8b1-f8f8f8f8f8f8' - end - end - end - end - end -end diff --git a/app/swagger_docs/swagger_docs.rb b/app/swagger_docs/swagger_docs.rb index 0ae2e11..cf44259 100644 --- a/app/swagger_docs/swagger_docs.rb +++ b/app/swagger_docs/swagger_docs.rb @@ -3,6 +3,8 @@ class SwaggerDocs include Swagger::Blocks + CONTACT_CLASSES = ApplicationContract.contract_classes + SWAGGERED_CLASSES = [ ## Controllers ## Controllers::Users::TokensController, @@ -13,9 +15,6 @@ class SwaggerDocs Models::Meta, ## Inputs ## Inputs::User::SignInInput, - Inputs::User::SignUpInput, - Inputs::User::ResetPasswordInput, - Inputs::User::UpdatePasswordInput, Inputs::User::RevokeInput, ## Responses ## Responses::User::SignInResponse, @@ -24,7 +23,7 @@ class SwaggerDocs Responses::User::UpdatePasswordResponse, Responses::ErrorResponse, self - ].freeze + ].concat(CONTACT_CLASSES).freeze swagger_root do key :openapi, '3.0.0' diff --git a/config/initializers/dry_schema.rb b/config/initializers/dry_schema.rb new file mode 100644 index 0000000..710deaa --- /dev/null +++ b/config/initializers/dry_schema.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +Dry::Schema.load_extensions(:json_schema) diff --git a/config/locales/contracts/tr.yml b/config/locales/contracts/tr.yml index 6ae8447..668e4f8 100644 --- a/config/locales/contracts/tr.yml +++ b/config/locales/contracts/tr.yml @@ -7,12 +7,18 @@ tr: params: email: E-posta password: Şifre + client_id: 'İstemci kimliği' + client_secret: 'İstemci parolası' passwords: updatecontract: params: password: Şifre password_confirmation: Şifre onayı reset_password_token: Şifre sıfırlama jetonu + client_id: 'İstemci kimliği' + client_secret: 'İstemci parolası' sendinstructionscontract: params: email: E-posta + client_id: 'İstemci kimliği' + client_secret: 'İstemci parolası' diff --git a/docs/SWAGGER.md b/docs/SWAGGER.md index 5d4d116..0156558 100644 --- a/docs/SWAGGER.md +++ b/docs/SWAGGER.md @@ -53,6 +53,41 @@ end ``` --- ### Sample input +All contracts are generating automatically as swagger input components for using easily. + +**Auto generated:** + +Sample contract: +```ruby +# frozen_string_literal: true + +module Users + module Passwords + class SendInstructionsContract < ApplicationContract + params do + required(:email).filled(Types::Email) + required(:client_id).filled(:string) + required(:client_secret).filled(:string) + end + end + end +end +``` + +You can use just referring name as belowing: +```ruby +request_body do + key :description, 'User credentials' + key :required, true + content :'application/json' do + schema do + key :'$ref', :UsersPasswordsSendInstructionsContractInput + end + end +end +``` + +**Custom:** ```ruby # frozen_string_literal: true diff --git a/lib/supports/application_contract/swagger_input.rb b/lib/supports/application_contract/swagger_input.rb new file mode 100644 index 0000000..55031c9 --- /dev/null +++ b/lib/supports/application_contract/swagger_input.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'active_support/all' + +module Supports + module ApplicationContract + module SwaggerInput + extend ActiveSupport::Concern + + module ClassMethods + def _swagger_nodes + { component_node: OpenStruct.new(data: component_node_data) } + end + + def contract_classes + Dir[Rails.root.join('app/contracts/**/*_contract.rb')].map do |path| + klass = path.split('/app/contracts/') + .last + .rpartition('.') + .first + .classify + .constantize + + next if klass.eql?(::ApplicationContract) + + klass + end.reject(&:blank?) + end + + private + + def custom_schema_name + "#{name.gsub('::', '')}Input".to_sym + end + + def custom_json_schema + json_schema = schema.json_schema(loose: true) + + { + type: json_schema[:type], + properties: json_schema[:properties], + required: json_schema[:required] + } + end + + def component_node_data + { schemas: { "#{custom_schema_name}": custom_json_schema } } + end + end + end + end +end