diff --git a/config/routes.rb b/config/routes.rb index 4d075165..bd319530 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,9 +25,19 @@ if Spree::Core::Engine.frontend_available? resources :users, only: [:edit, :update] - get '/checkout/registration' => 'checkout#registration', :as => :checkout_registration - put '/checkout/registration' => 'checkout#update_registration', :as => :update_checkout_registration resource :account, controller: 'users' + + unless Spree::Auth::Engine.checkout_available? + get '/checkout/registration' => 'checkout#registration', :as => :checkout_registration + put '/checkout/registration' => 'checkout#update_registration', :as => :update_checkout_registration + end + end + + if Spree::Auth::Engine.checkout_available? + namespace :checkout do + get :registration, to: 'orders#registration', as: :registration + put :registration, to: 'orders#update_registration', as: :update_registration + end end if Spree.respond_to?(:admin_path) && Spree::Core::Engine.backend_available? diff --git a/lib/controllers/checkout/spree/auth/checkout/orders_controller_decorator.rb b/lib/controllers/checkout/spree/auth/checkout/orders_controller_decorator.rb new file mode 100644 index 00000000..f45b01f6 --- /dev/null +++ b/lib/controllers/checkout/spree/auth/checkout/orders_controller_decorator.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module Spree + module Auth + module Checkout + # + # Adds methods to Spree Checkout Orders + module OrdersControllerDecorator + def self.prepended(base) + base.before_action :check_authorization + base.before_action :check_registration, except: %i[registration update_registration] + end + + def registration + @user = Spree.user_class.new + @title = Spree.t(:registration) + end + + def update_registration + if order_params[:email] =~ Devise.email_regexp && current_order.update_attribute(:email, order_params[:email]) + redirect_to spree.checkout_state_path(:address) + else + flash[:error] = t(:email_is_invalid, scope: %i[errors messages]) + @user = Spree.user_class.new + render 'registration', status: :unprocessable_entity + end + end + + private + + def order_params + params[:order].present? ? params.require(:order).permit(:email) : {} + end + + def skip_state_validation? + %w[registration update_registration].include?(params[:action]) + end + + def check_authorization + authorize!(:edit, current_order, cookies.signed[:guest_token]) + end + + # Introduces a registration step whenever the +registration_step+ preference is true. + def check_registration + return unless Spree::Auth::Config[:registration_step] + return if spree_current_user || current_order.email + + store_location + redirect_to spree.checkout_registration_path + end + + Spree::Checkout::OrdersController.prepend(self) if ::Spree::Checkout::OrdersController.included_modules.exclude?(self) + end + end + end +end diff --git a/lib/controllers/checkout/spree/user_sessions_controller.rb b/lib/controllers/checkout/spree/user_sessions_controller.rb new file mode 100644 index 00000000..690116b2 --- /dev/null +++ b/lib/controllers/checkout/spree/user_sessions_controller.rb @@ -0,0 +1,86 @@ +class Spree::UserSessionsController < Devise::SessionsController + helper 'spree/base' + + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Store + + include SpreeI18n::ControllerLocaleHelper if defined?(SpreeI18n::ControllerLocaleHelper) + + include Spree::Core::ControllerHelpers::Currency if defined?(Spree::Core::ControllerHelpers::Currency) + include Spree::Core::ControllerHelpers::Locale if defined?(Spree::Core::ControllerHelpers::Locale) + + include Spree::LocaleUrls if defined?(Spree::LocaleUrls) + + helper 'spree/locale' if defined?(Spree::LocaleHelper) + helper 'spree/currency' if defined?(Spree::CurrencyHelper) + helper 'spree/store' if defined?(Spree::StoreHelper) + + before_action :set_current_order + + def create + authenticate_spree_user! + + if spree_user_signed_in? + respond_to do |format| + format.html { + flash[:success] = Spree.t(:logged_in_successfully) + redirect_back_or_default(after_sign_in_redirect(spree_current_user)) + } + format.js { + render json: { user: spree_current_user, + ship_address: spree_current_user.ship_address, + bill_address: spree_current_user.bill_address }.to_json + } + end + else + respond_to do |format| + format.html { + flash.now[:error] = t('devise.failure.invalid') + render :new, status: :unprocessable_entity + } + format.js { + render json: { error: t('devise.failure.invalid') }, status: :unprocessable_entity + } + end + end + end + + protected + + def translation_scope + 'devise.user_sessions' + end + + private + + def accurate_title + Spree.t(:login) + end + + def redirect_back_or_default(default) + redirect_to(session["spree_user_return_to"] || default) + session["spree_user_return_to"] = nil + end + + def after_sign_in_redirect(resource_or_scope) + stored_location_for(resource_or_scope) || spree.account_path + end + + def respond_to_on_destroy + # We actually need to hardcode this as Rails default responder doesn't + # support returning empty response on GET request + respond_to do |format| + format.all { head :no_content } + format.any(*navigational_formats) { redirect_to after_sign_out_redirect(resource_name) } + end + end + + def after_sign_out_redirect(resource_or_scope) + scope = Devise::Mapping.find_scope!(resource_or_scope) + router_name = Devise.mappings[scope].router_name + context = router_name ? send(router_name) : self + context.respond_to?(:login_path) ? context.login_path(locale_param) : spree.root_path + end +end diff --git a/lib/spree/auth/engine.rb b/lib/spree/auth/engine.rb index 01ed4480..081186af 100644 --- a/lib/spree/auth/engine.rb +++ b/lib/spree/auth/engine.rb @@ -30,6 +30,11 @@ def self.activate Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c| Rails.configuration.cache_classes ? require(c) : load(c) end + if Spree::Auth::Engine.checkout_available? + Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/checkout/**/*_decorator*.rb")) do |c| + Rails.configuration.cache_classes ? require(c) : load(c) + end + end if Spree::Auth::Engine.backend_available? Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/backend/*/*/*_decorator*.rb")) do |c| Rails.configuration.cache_classes ? require(c) : load(c) @@ -45,11 +50,12 @@ def self.activate Rails.configuration.cache_classes ? require(c) : load(c) end end + ApplicationController.send :include, Spree::AuthenticationHelpers end - def self.api_available? - @@api_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Api::Engine') + def self.checkout_available? + @@checkout_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Checkout::Engine') end def self.backend_available? @@ -68,6 +74,11 @@ def self.emails_available? @@emails_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Emails::Engine') end + if checkout_available? + paths["app/controllers"] << "lib/controllers/checkout" + paths["app/views"] << "lib/views/checkout" + end + if backend_available? paths["app/controllers"] << "lib/controllers/backend" paths["app/views"] << "lib/views/backend"