From 8f1e9f792bdb1cc6ffba204546a75e40ab0450f4 Mon Sep 17 00:00:00 2001 From: Oleg Leontiev Date: Tue, 19 May 2020 10:21:10 +0200 Subject: [PATCH 1/6] add storefront AccountControllerDecorator --- .../account_controller_decorator.rb | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 app/controllers/spree/api/v2/storefront/account_controller_decorator.rb diff --git a/app/controllers/spree/api/v2/storefront/account_controller_decorator.rb b/app/controllers/spree/api/v2/storefront/account_controller_decorator.rb new file mode 100644 index 000000000..23254f450 --- /dev/null +++ b/app/controllers/spree/api/v2/storefront/account_controller_decorator.rb @@ -0,0 +1,28 @@ +module Spree + module Api + module V2 + module Storefront + module AccountControllerDecorator + def self.prepended(base) + base.skip_before_action :require_spree_current_user, only: [:create] + end + + def create + user = build_resource(spree_user_params) + if user.save + render_serialized_payload { serialize_resource(user) } + else + render json: {error: 'error'} + end + end + + def spree_user_params + params.require(:spree_user).permit(Spree::PermittedAttributes.user_attributes) + end + end + end + end + end +end + +Spree::Api::V2::Storefront::AccountController.prepend(Spree::Api::V2::Storefront::AccountControllerDecorator) From ce7538576fb7651908426995fa709e8a8843fbdc Mon Sep 17 00:00:00 2001 From: Oleg Leontiev Date: Tue, 19 May 2020 10:29:06 +0200 Subject: [PATCH 2/6] add route --- config/routes.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/routes.rb b/config/routes.rb index 29409609e..fc6a1b6a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -44,4 +44,12 @@ get '/logout' => 'user_sessions#destroy', :as => :logout end end + + namespace :api, defaults: { format: 'json' } do + namespace :v2 do + namespace :storefront do + resource :account, controller: :account, only: %i[show create] + end + end + end end From 213990bd3265b0629a63e33e89c176ddd4b9745e Mon Sep 17 00:00:00 2001 From: Oleg Leontiev Date: Tue, 19 May 2020 12:26:32 +0200 Subject: [PATCH 3/6] move decorator --- .../api/v2/storefront/account_controller_decorator.rb | 8 ++++---- lib/spree/auth/engine.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename {app/controllers => lib/controllers/frontend}/spree/api/v2/storefront/account_controller_decorator.rb (59%) diff --git a/app/controllers/spree/api/v2/storefront/account_controller_decorator.rb b/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb similarity index 59% rename from app/controllers/spree/api/v2/storefront/account_controller_decorator.rb rename to lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb index 23254f450..eb2a92e99 100644 --- a/app/controllers/spree/api/v2/storefront/account_controller_decorator.rb +++ b/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb @@ -8,16 +8,16 @@ def self.prepended(base) end def create - user = build_resource(spree_user_params) + user = Spree.user_class.new_with_session(spree_user_params, session) if user.save render_serialized_payload { serialize_resource(user) } else - render json: {error: 'error'} + render json: { errors: user.errors.messages } end end def spree_user_params - params.require(:spree_user).permit(Spree::PermittedAttributes.user_attributes) + params.require(:user).permit(Spree::PermittedAttributes.user_attributes) end end end @@ -25,4 +25,4 @@ def spree_user_params end end -Spree::Api::V2::Storefront::AccountController.prepend(Spree::Api::V2::Storefront::AccountControllerDecorator) +::Spree::Api::V2::Storefront::AccountController.prepend(Spree::Api::V2::Storefront::AccountControllerDecorator) diff --git a/lib/spree/auth/engine.rb b/lib/spree/auth/engine.rb index acf5610cf..443879e73 100644 --- a/lib/spree/auth/engine.rb +++ b/lib/spree/auth/engine.rb @@ -42,7 +42,7 @@ def self.activate 'lib/assets/javascripts/spree/frontend/spree_auth.js', 'lib/assets/javascripts/spree/frontend/spree_auth.css' ] - Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/frontend/*/*_decorator*.rb")) do |c| + Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/frontend/**/*_decorator*.rb")) do |c| Rails.configuration.cache_classes ? require(c) : load(c) end end From 52456181685732babbc8ee0f834802fffd74940d Mon Sep 17 00:00:00 2001 From: Oleg Leontiev Date: Tue, 19 May 2020 13:08:22 +0200 Subject: [PATCH 4/6] use error struct --- .../account_controller_decorator.rb | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb b/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb index eb2a92e99..2e674dbf9 100644 --- a/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb +++ b/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb @@ -8,17 +8,35 @@ def self.prepended(base) end def create - user = Spree.user_class.new_with_session(spree_user_params, session) + user = Spree.user_class.new(spree_user_params) if user.save render_serialized_payload { serialize_resource(user) } else - render json: { errors: user.errors.messages } + render_error_payload(structed_error(user.errors)) end end def spree_user_params params.require(:user).permit(Spree::PermittedAttributes.user_attributes) end + + def structed_error(error) + struct_error = Struct.new(:error) do + def to_s + return error.full_messages.join(', ') if error&.respond_to?(:full_messages) + + value.to_s + end + + def to_h + return error.messages if error&.respond_to?(:messages) + + {} + end + end + + struct_error.new(error) + end end end end From 3255b49e1a92b2bf43766fe662881228893d2afb Mon Sep 17 00:00:00 2001 From: Oleg Leontiev Date: Tue, 19 May 2020 13:34:40 +0200 Subject: [PATCH 5/6] spec --- .../spree/api/v2/storefront/account_spec.rb | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 spec/requests/spree/api/v2/storefront/account_spec.rb diff --git a/spec/requests/spree/api/v2/storefront/account_spec.rb b/spec/requests/spree/api/v2/storefront/account_spec.rb new file mode 100644 index 000000000..8d3b5853d --- /dev/null +++ b/spec/requests/spree/api/v2/storefront/account_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe 'Storefront API v2 Account spec', type: :request do + describe 'account#create' do + before { post '/api/v2/storefront/account', params: params } + + context 'valid user params' do + let(:params) do + { + "user": { + "email": "hello@example.com", + "password": "password123", + "password_confirmation": "password123" + } + } + end + + it_behaves_like 'returns 200 HTTP status' + + it 'return JSON API payload of User' do + expect(JSON.parse(response.body)['data']['attributes']['email']).to eq('hello@example.com') + end + end + + context 'invalid user params' do + let(:params) do + { + "user": { + "email": "hello@example.com", + "password": "password123", + "password_confirmation": "" + } + } + end + + it 'return JSON API payload of error' do + expect(JSON.parse(response.body)['error']).to eq("Password Confirmation doesn't match Password") + end + end + + end +end From 906397783d563cb85b3284110ecbd43c6c0ea247 Mon Sep 17 00:00:00 2001 From: Damian Legawiec Date: Tue, 19 May 2020 17:01:50 +0200 Subject: [PATCH 6/6] Move controller to proper namespace, utilize Service pattern --- app/services/spree/account/create.rb | 19 ++++++++ .../account_controller_decorator.rb | 29 ++++++++++++ .../account_controller_decorator.rb | 46 ------------------- lib/spree/auth/engine.rb | 13 ++++++ 4 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 app/services/spree/account/create.rb create mode 100644 lib/controllers/api/spree/v2/storefront/account_controller_decorator.rb delete mode 100644 lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb diff --git a/app/services/spree/account/create.rb b/app/services/spree/account/create.rb new file mode 100644 index 000000000..8713f6957 --- /dev/null +++ b/app/services/spree/account/create.rb @@ -0,0 +1,19 @@ +module Spree + module Account + class Create + prepend Spree::ServiceModule::Base + + def call(user_params: nil) + user_params ||= {} + + user = Spree.user_class.new(user_params) + + if user.save + success(user) + else + failure(user) + end + end + end + end +end diff --git a/lib/controllers/api/spree/v2/storefront/account_controller_decorator.rb b/lib/controllers/api/spree/v2/storefront/account_controller_decorator.rb new file mode 100644 index 000000000..649a3972b --- /dev/null +++ b/lib/controllers/api/spree/v2/storefront/account_controller_decorator.rb @@ -0,0 +1,29 @@ +module Spree + module Api + module V2 + module Storefront + module AccountControllerDecorator + def self.prepended(base) + base.skip_before_action :require_spree_current_user, only: [:create] + end + + def create + result = Spree::Account::Create.call(user_params: spree_user_params) + + if result.success? + render_serialized_payload { serialize_resource(result.value) } + else + render_error_payload(result.error) + end + end + + def spree_user_params + params.require(:user).permit(Spree::PermittedAttributes.user_attributes) + end + end + end + end + end +end + +::Spree::Api::V2::Storefront::AccountController.prepend(Spree::Api::V2::Storefront::AccountControllerDecorator) diff --git a/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb b/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb deleted file mode 100644 index 2e674dbf9..000000000 --- a/lib/controllers/frontend/spree/api/v2/storefront/account_controller_decorator.rb +++ /dev/null @@ -1,46 +0,0 @@ -module Spree - module Api - module V2 - module Storefront - module AccountControllerDecorator - def self.prepended(base) - base.skip_before_action :require_spree_current_user, only: [:create] - end - - def create - user = Spree.user_class.new(spree_user_params) - if user.save - render_serialized_payload { serialize_resource(user) } - else - render_error_payload(structed_error(user.errors)) - end - end - - def spree_user_params - params.require(:user).permit(Spree::PermittedAttributes.user_attributes) - end - - def structed_error(error) - struct_error = Struct.new(:error) do - def to_s - return error.full_messages.join(', ') if error&.respond_to?(:full_messages) - - value.to_s - end - - def to_h - return error.messages if error&.respond_to?(:messages) - - {} - end - end - - struct_error.new(error) - end - end - end - end - end -end - -::Spree::Api::V2::Storefront::AccountController.prepend(Spree::Api::V2::Storefront::AccountControllerDecorator) diff --git a/lib/spree/auth/engine.rb b/lib/spree/auth/engine.rb index 443879e73..ebe0d397c 100644 --- a/lib/spree/auth/engine.rb +++ b/lib/spree/auth/engine.rb @@ -46,6 +46,11 @@ def self.activate Rails.configuration.cache_classes ? require(c) : load(c) end end + if Spree::Auth::Engine.api_available? + Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/api/**/*_decorator*.rb")) do |c| + Rails.configuration.cache_classes ? require(c) : load(c) + end + end ApplicationController.send :include, Spree::AuthenticationHelpers end @@ -61,6 +66,10 @@ def self.frontend_available? @@frontend_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Frontend::Engine') end + def self.api_available? + @@api_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Api::Engine') + end + if backend_available? paths["app/controllers"] << "lib/controllers/backend" paths["app/views"] << "lib/views/backend" @@ -71,6 +80,10 @@ def self.frontend_available? paths["app/views"] << "lib/views/frontend" end + if api_available? + paths["app/controllers"] << "lib/controllers/api" + end + config.to_prepare &method(:activate).to_proc end end