-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add UserReturnToStorer service object
Spree::UserReturnToStorer can be used to selectively store the current path in `session[:spree_user_return_to]`. This object allows easy extension/change of behavior by using a list of rules. When at least one rule is matched, the request path is not stored in session. The class ships with the default rule AutenticationRule, that was extacted from Spree::Core::ControllerHelpers::Auth#store_location
- Loading branch information
1 parent
f80912a
commit 6c20ca0
Showing
5 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# frozen_string_literal: true | ||
|
||
module Spree | ||
# This service object is responsible for storing the current path into | ||
# into `session[:spree_user_return_to]` for redirects after successful | ||
# user/admin authentication. | ||
class UserReturnToStorer | ||
class Configuration | ||
def rules | ||
@rules ||= ::Spree::Core::ClassConstantizer::Set.new.tap do |set| | ||
set << 'Spree::UserReturnToStorer::Rules::AuthenticationRule' | ||
end | ||
end | ||
end | ||
|
||
# Lists all the rules that will be evaluated before storing the | ||
# current path value into the session. | ||
# | ||
# @return [Spree::Core::ClassConstantizer::Set] a set of rules | ||
# that, when matched, will prevent session[:spree_user_return_to] | ||
# to be set | ||
# | ||
# @example This method can be used also to add more rules | ||
# Spree::UserReturnToStorer.rules << 'CustomRule' | ||
# | ||
# @examle it can be used also removing unwanted rules | ||
# Spree::UserReturnToStorer.rules.delete('CustomRule') | ||
# | ||
def self.rules | ||
Spree::Config.user_return_to_storer.rules | ||
end | ||
|
||
# @param controller [ApplicationController] an instance of ApplicationController | ||
# or its subclasses. The controller will be passed to each rule for matching. | ||
def initialize(controller) | ||
@controller = controller | ||
end | ||
|
||
# Stores into session[:spree_user_return_to] the request full path for | ||
# future redirects (to be used after successful authentication). When | ||
# there is a rule match then the request full path is not stored. | ||
def store_location | ||
return if self.class.rules.any? { |rule| rule.match? controller } | ||
|
||
session[:spree_user_return_to] = request.fullpath.gsub('//', '/') | ||
end | ||
|
||
private | ||
|
||
attr_reader :controller | ||
|
||
delegate :session, :request, to: :controller | ||
end | ||
end |
35 changes: 35 additions & 0 deletions
35
core/app/models/spree/user_return_to_storer/rules/authentication_rule.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# frozen_string_literal: true | ||
|
||
module Spree | ||
class UserReturnToStorer | ||
module Rules | ||
# This is the basic rule that ships with Solidus that avoids storing in | ||
# session the current path for login/loout/signup routes, avoiding possibly | ||
# infinte redirects. | ||
module AuthenticationRule | ||
AUTHENTICATION_ROUTES = %w[spree_signup_path spree_login_path spree_logout_path] | ||
|
||
extend self | ||
|
||
def match?(controller) | ||
full_path = controller.request.fullpath | ||
disallowed_urls(controller).include?(full_path) | ||
end | ||
|
||
private | ||
|
||
def disallowed_urls(controller) | ||
@disallowed_urls ||= begin | ||
[].tap do |disallowed_urls| | ||
AUTHENTICATION_ROUTES.each do |route| | ||
if controller.respond_to?(route) | ||
disallowed_urls << controller.send(route) | ||
end | ||
end | ||
end.map! { |url| url[/\/\w+$/] } | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
core/spec/models/spree/user_return_to_storer/rules/authentication_rule_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe Spree::UserReturnToStorer::Rules::AuthenticationRule do | ||
describe '#match?' do | ||
let(:login_path) { '/sign_in' } | ||
let(:request) { double(fullpath: fullpath) } | ||
let(:controller) do | ||
double( | ||
request: request, | ||
spree_login_path: login_path | ||
) | ||
end | ||
|
||
subject { described_class.match?(controller) } | ||
|
||
context 'when the request full path is an authentication route' do | ||
let!(:fullpath) { login_path } | ||
|
||
it { is_expected.to be true } | ||
end | ||
|
||
context 'when the request full path is not an authentication route' do | ||
let!(:fullpath) { '/products/baseball-cap' } | ||
|
||
it { is_expected.to be false } | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe Spree::UserReturnToStorer do | ||
subject { described_class.new(controller) } | ||
|
||
let(:fullpath) { '/products/baseball-cap' } | ||
let(:session) { {} } | ||
let(:request) { double(fullpath: fullpath) } | ||
let(:controller) do | ||
instance_double( | ||
ApplicationController, | ||
request: request, | ||
session: session | ||
) | ||
end | ||
|
||
module CustomRule | ||
def self.match?(_controller) | ||
true | ||
end | ||
end | ||
|
||
after :each do | ||
described_class.rules.delete('CustomRule') | ||
end | ||
|
||
describe '::rules' do | ||
it 'includes default rules' do | ||
rule = Spree::UserReturnToStorer::Rules::AuthenticationRule | ||
expect(described_class.rules).to include(rule) | ||
end | ||
|
||
it 'can add new rules' do | ||
described_class.rules << CustomRule | ||
expect(described_class.rules).to include(CustomRule) | ||
end | ||
end | ||
|
||
describe '#store_location' do | ||
context 'when at least one rule matches' do | ||
it 'does not set the path value into the session' do | ||
described_class.rules << CustomRule | ||
subject.store_location | ||
expect(session[:spree_user_return_to]).to be_nil | ||
end | ||
end | ||
|
||
context 'when no rule matches' do | ||
it 'sets the path value into the session' do | ||
described_class.rules << CustomRule | ||
described_class.rules.delete('CustomRule') | ||
subject.store_location | ||
expect(session[:spree_user_return_to]).to eql fullpath | ||
end | ||
end | ||
end | ||
end |