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/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 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/spree/auth/engine.rb b/lib/spree/auth/engine.rb index acf5610cf..ebe0d397c 100644 --- a/lib/spree/auth/engine.rb +++ b/lib/spree/auth/engine.rb @@ -42,7 +42,12 @@ 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 + 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 @@ -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 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