omniauth-multiprovider 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +13 -18
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/{LICENSE → LICENSE.txt} +0 -0
- data/README.md +52 -7
- data/Rakefile +2 -0
- data/lib/omniauth-multiprovider.rb +3 -1
- data/lib/omniauth/multiprovider.rb +0 -1
- data/lib/omniauth/multiprovider/config.rb +25 -0
- data/lib/omniauth/multiprovider/controllers/callbacks_controller.rb +43 -3
- data/lib/omniauth/multiprovider/error.rb +24 -1
- data/lib/omniauth/multiprovider/models/active_record.rb +14 -0
- data/lib/omniauth/multiprovider/models/authentication.rb +1 -9
- data/lib/omniauth/multiprovider/models/concerns/omni_authenticable.rb +79 -32
- data/lib/omniauth/multiprovider/version.rb +1 -1
- data/lib/omniauth/provider/abstract.rb +6 -38
- data/lib/omniauth/provider/generic.rb +10 -13
- data/omniauth-multiprovider.gemspec +15 -2
- data/spec/omniauth/error_spec.rb +30 -0
- data/spec/omniauth/multiprovider/controllers/callbacks_controller_spec.rb +90 -0
- data/spec/omniauth/multiprovider/models/active_record_spec.rb +21 -0
- data/spec/omniauth/multiprovider/models/concerns/omni_authenticable_spec.rb +67 -0
- data/spec/omniauth/provider/abstract_spec.rb +15 -0
- data/spec/omniauth/provider/facebook_spec.rb +13 -0
- data/spec/omniauth/provider/generic_spec.rb +13 -0
- data/spec/rails_app/.gitignore +17 -0
- data/spec/rails_app/Rakefile +6 -0
- data/spec/rails_app/app/assets/images/.keep +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +16 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
- data/spec/rails_app/app/controllers/application_controller.rb +5 -0
- data/spec/rails_app/app/controllers/concerns/.keep +0 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.keep +0 -0
- data/spec/rails_app/app/models/.keep +0 -0
- data/spec/rails_app/app/models/concerns/.keep +0 -0
- data/spec/rails_app/app/models/user.rb +4 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/bin/bundle +3 -0
- data/spec/rails_app/bin/rails +4 -0
- data/spec/rails_app/bin/rake +4 -0
- data/spec/rails_app/bin/setup +29 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +26 -0
- data/spec/rails_app/config/boot.rb +3 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/test.rb +42 -0
- data/spec/rails_app/config/initializers/assets.rb +11 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/rails_app/config/initializers/devise.rb +259 -0
- data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/rails_app/config/initializers/mime_types.rb +4 -0
- data/spec/rails_app/config/initializers/session_store.rb +3 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/en.yml +23 -0
- data/spec/rails_app/config/routes.rb +3 -0
- data/spec/rails_app/config/secrets.yml +22 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/lib/assets/.keep +0 -0
- data/spec/rails_app/lib/tasks/.keep +0 -0
- data/spec/rails_app/public/404.html +67 -0
- data/spec/rails_app/public/422.html +67 -0
- data/spec/rails_app/public/500.html +66 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/shared_examples_for_providers.rb +27 -0
- metadata +226 -7
- data/lib/omniauth/multiprovider/helpers.rb +0 -23
- data/lib/omniauth/provider/guests.rb +0 -12
@@ -1,46 +1,14 @@
|
|
1
1
|
module OmniAuth
|
2
2
|
module Provider
|
3
|
-
class Abstract
|
3
|
+
class Abstract < SimpleDelegator
|
4
4
|
|
5
|
-
def
|
5
|
+
def initialize(controller)
|
6
|
+
super
|
7
|
+
@controller = controller
|
6
8
|
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
def self.find_from_oauth(provider_name, omniauth_data, signed_in_resource=nil)
|
11
|
-
auth = MultiProvider::authentication_klass.normalize(omniauth_data)
|
12
|
-
access_token = auth.credentials.token
|
13
|
-
authentication = MultiProvider.authentication_klass.find_by(provider: provider_name, uid: auth.uid)
|
14
|
-
|
15
|
-
resource = nil
|
16
|
-
|
17
|
-
if authentication
|
18
|
-
if signed_in_resource
|
19
|
-
if authentication.resource == signed_in_resource
|
20
|
-
raise MultiProvider::Error.new 'already connected'
|
21
|
-
else
|
22
|
-
raise MultiProvider::Error.new 'already connected with other user'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
resource = authentication.resource
|
26
|
-
end
|
27
|
-
unless resource
|
28
|
-
if auth.info[:email].blank?
|
29
|
-
auth.info[:email] = MultiProvider::resource_klass.mock_email(provider_name, auth.uid)
|
30
|
-
end
|
31
|
-
email = auth.info[:email]
|
32
|
-
|
33
|
-
raise MultiProvider::Error.new 'email_already_registered' if MultiProvider::resource_klass.find_by(email: email)
|
34
|
-
|
35
|
-
resource = signed_in_resource || MultiProvider::resource_klass.new(
|
36
|
-
email: email,
|
37
|
-
password: Devise.friendly_token[0,20]
|
38
|
-
)
|
39
|
-
|
40
|
-
MultiProvider.authentication_klass.from(auth, resource)
|
41
|
-
|
42
|
-
end
|
43
|
-
resource
|
10
|
+
def handle_request(controller)
|
11
|
+
raise "Should be defined by subclasses"
|
44
12
|
end
|
45
13
|
|
46
14
|
def self.authenticate_from_oauth(provider_name, omniauth_data)
|
@@ -2,21 +2,18 @@ module OmniAuth
|
|
2
2
|
module Provider
|
3
3
|
class Generic < Abstract
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
if resource
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
redirect_to send("new_#{OmniAuth::MultiProvider::resource_mapping}_registration_url")
|
16
|
-
end
|
5
|
+
def handle_request
|
6
|
+
auth = request.env['omniauth.auth']
|
7
|
+
provider_name = auth['provider_name']
|
8
|
+
resource = resource_class.from_oauth auth, signed_in_resource
|
9
|
+
if resource.persisted?
|
10
|
+
sign_in_and_redirect resource, event: :authentication #this will throw if resource is not activated
|
11
|
+
@controller.send(:set_flash_message, :notice, :success, kind: provider_name.to_s.camelize) if is_navigational_format?
|
12
|
+
else
|
13
|
+
session["devise.#{provider_name}_data"] = auth.except('extra')
|
14
|
+
redirect_to send("new_#{OmniAuth::MultiProvider::resource_mapping}_registration_url")
|
17
15
|
end
|
18
16
|
end
|
19
|
-
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
2
5
|
require 'omniauth/multiprovider/version'
|
3
6
|
|
4
7
|
Gem::Specification.new do |s|
|
@@ -8,12 +11,22 @@ Gem::Specification.new do |s|
|
|
8
11
|
s.description = "Provides a simple approach to support many oauth providers to devise"
|
9
12
|
s.authors = ["German Del Zotto"]
|
10
13
|
s.email = 'germ@ndz.com.ar'
|
11
|
-
s.files = `git ls-files`.split("\
|
14
|
+
s.files = `git ls-files -z`.split("\x0")
|
15
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
12
16
|
s.require_paths = ['lib']
|
13
17
|
s.homepage = 'https://github.com/1uptalent/omniauth-multiprovider'
|
14
18
|
s.license = 'MIT'
|
15
19
|
|
16
20
|
s.add_dependency('devise', '~> 3.2')
|
21
|
+
s.add_dependency('activesupport', ">= 3.2.6", "< 5")
|
22
|
+
s.add_dependency('activerecord', ">= 3.2.6", "< 5")
|
17
23
|
s.add_dependency('omniauth-oauth2', '~> 1.1')
|
18
24
|
s.add_dependency('hashugar', '~> 0.0', '>= 0.0.6')
|
25
|
+
|
26
|
+
s.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
s.add_development_dependency "rake", "~> 10.0"
|
28
|
+
|
29
|
+
s.add_development_dependency "rspec", "~> 3.1"
|
30
|
+
s.add_development_dependency "rspec-rails", "~> 3.1"
|
31
|
+
s.add_development_dependency "sqlite3"
|
19
32
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OmniAuth::MultiProvider::Error do
|
4
|
+
it 'is a runtime error' do
|
5
|
+
expect { raise OmniAuth::MultiProvider::Error }.to raise_error RuntimeError
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe OmniAuth::MultiProvider::AlreadyBoundError do
|
10
|
+
let(:current_resource) { double('current_resource') }
|
11
|
+
let(:bound_resource) { double("bound_resource") }
|
12
|
+
|
13
|
+
it 'provides the current and bound resources' do
|
14
|
+
error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, bound_resource)
|
15
|
+
expect(error.bound_to).to be bound_resource
|
16
|
+
expect(error.current).to be current_resource
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#message' do
|
20
|
+
it 'is "bound_to_same" for the same current and bound resource' do
|
21
|
+
error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, current_resource)
|
22
|
+
expect(error.message).to eq 'bound_to_same'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is "bound_to_other" for different current and bound resources' do
|
26
|
+
error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, bound_resource)
|
27
|
+
expect(error.message).to eq 'bound_to_other'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'OmniAuth::MultiProvider::CallbacksController' do
|
4
|
+
let(:klass) { OmniAuth::MultiProvider::CallbacksController }
|
5
|
+
|
6
|
+
it 'defines methods for omniauth providers' do
|
7
|
+
Devise.omniauth :foo
|
8
|
+
Devise.omniauth :bar
|
9
|
+
methods = klass.action_methods
|
10
|
+
expect(methods).to include 'foo'
|
11
|
+
expect(methods).to include 'bar'
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#create_handler' do
|
15
|
+
it 'creates a method with the handler name' do
|
16
|
+
klass.send :create_handler, 'whatever'
|
17
|
+
expect(klass.action_methods).to include 'whatever'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'creates a generic handler for unknown providers' do
|
21
|
+
expect_any_instance_of(OmniAuth::Provider::Generic).to receive :handle_request
|
22
|
+
klass.send :create_handler, 'whatever'
|
23
|
+
klass.new.whatever
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'creates a custom handler for Facebook' do
|
27
|
+
expect_any_instance_of(OmniAuth::Provider::Facebook).to receive :handle_request
|
28
|
+
klass.send :create_handler, 'facebook'
|
29
|
+
klass.new.facebook
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#handle_request' do
|
34
|
+
subject { klass.new }
|
35
|
+
let(:request) { ActionDispatch::TestRequest.new }
|
36
|
+
let(:response) { ActionDispatch::TestResponse.new }
|
37
|
+
before { klass.send :public, :handle_request }
|
38
|
+
before { allow(subject).to receive(:devise_mapping) { Devise.mappings[:user]} }
|
39
|
+
before do
|
40
|
+
subject.instance_variable_set '@_request', request
|
41
|
+
subject.instance_variable_set '@_response', response
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when it raises' do
|
45
|
+
let(:provider) { double('a provider') }
|
46
|
+
|
47
|
+
context 'MultiProvider errors' do
|
48
|
+
let(:error) { OmniAuth::MultiProvider::Error.new 'message_key' }
|
49
|
+
before { expect(provider).to receive(:handle_request).and_raise(error) }
|
50
|
+
|
51
|
+
context 'default behavior' do
|
52
|
+
it 'does not raise' do
|
53
|
+
expect { subject.handle_request provider }.not_to raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'sets the flash[:alert] with an I18N error message' do
|
57
|
+
subject.handle_request provider
|
58
|
+
expect(subject.flash[:alert]).to match %r{en.devise.callbacks.user.#{error.message}}
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'redirects to the remembered url' do
|
62
|
+
location = '/foo/bar/baz'
|
63
|
+
subject.store_location_for :user, location
|
64
|
+
subject.handle_request provider
|
65
|
+
expect(response.location).to eq "http://test.host#{location}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'does raise if the error is not handled' do
|
70
|
+
allow(subject).to receive(:handle_provider_error) { false }
|
71
|
+
expect { subject.handle_request provider }.to raise_error error
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'unexpected errors' do
|
76
|
+
let(:unexpected_error) { Class.new(RuntimeError).new("some message") }
|
77
|
+
before { expect(provider).to receive(:handle_request).and_raise(unexpected_error) }
|
78
|
+
it 're-raises the error by default' do
|
79
|
+
expect { subject.handle_request provider }.to raise_error unexpected_error
|
80
|
+
end
|
81
|
+
it 'does not raise if the error is handled' do
|
82
|
+
allow(subject).to receive(:handle_unexpected_error) { true }
|
83
|
+
expect { subject.handle_request provider }.not_to raise_error
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OmniAuth::MultiProvider::ActiveRecord do
|
4
|
+
before do
|
5
|
+
ActiveRecord::Base.connection.create_table :cs, temporary: true
|
6
|
+
end
|
7
|
+
after do
|
8
|
+
ActiveRecord::Base.connection.drop_table :cs
|
9
|
+
end
|
10
|
+
let!(:klass) do
|
11
|
+
class C < ActiveRecord::Base
|
12
|
+
omniauthenticable
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can create instances' do
|
17
|
+
klass.new
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OmniAuth::MultiProvider::OmniAuthenticable do
|
4
|
+
describe '#from_oauth' do
|
5
|
+
context 'already authenticated' do
|
6
|
+
let(:user) do
|
7
|
+
u = User.new
|
8
|
+
u.save validate: false
|
9
|
+
u
|
10
|
+
end
|
11
|
+
let(:authentication) do
|
12
|
+
Authentication.create(resource: user, provider: 'test', uid: '123')
|
13
|
+
end
|
14
|
+
let(:omniauth_data) do
|
15
|
+
#https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
|
16
|
+
{
|
17
|
+
provider: authentication.provider,
|
18
|
+
uid: authentication.uid,
|
19
|
+
credentials: { token: 'foo' }
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the existing user' do
|
24
|
+
expected = user
|
25
|
+
actual = User.from_oauth omniauth_data
|
26
|
+
expect(expected).to eq actual
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'fails if the current user is different' do
|
30
|
+
another_user = User.new
|
31
|
+
expect do
|
32
|
+
User.from_oauth omniauth_data, another_user
|
33
|
+
end.to raise_error OmniAuth::MultiProvider::AlreadyBoundError
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'succeeds if already bound to current user' do
|
37
|
+
expect do
|
38
|
+
User.from_oauth omniauth_data, user
|
39
|
+
end.not_to raise_error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#oauth_to_attributes' do
|
45
|
+
it 'returns email, password and password_confirmation' do
|
46
|
+
oauth = {provider: 'foo', info: { email: 'some_email' } }.to_hashugar
|
47
|
+
attrs = User.oauth_to_attributes oauth
|
48
|
+
expect(attrs.keys).to match [:email, :password, :password_confirmation]
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns a mock email when oauth data does not have it' do
|
52
|
+
oauth = {provider: 'foo', info: {} }.to_hashugar
|
53
|
+
email = User.oauth_to_attributes(oauth)[:email]
|
54
|
+
expect(email).to match /@from-foo\.example$/
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns the oauth email if present' do
|
58
|
+
oauth = {provider: 'foo', info: {email: 'smith@example.com'} }.to_hashugar
|
59
|
+
email = User.oauth_to_attributes(oauth)[:email]
|
60
|
+
expect(email).to eq 'smith@example.com'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#update_from_oauth' do
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/shared_examples_for_providers'
|
3
|
+
|
4
|
+
describe OmniAuth::Provider::Abstract do
|
5
|
+
let(:controller) { double('a controller') }
|
6
|
+
subject { described_class.new controller }
|
7
|
+
|
8
|
+
it_behaves_like 'a provider'
|
9
|
+
|
10
|
+
describe '#handle_request' do
|
11
|
+
it 'raises since it is a template method' do
|
12
|
+
expect{subject.handle_request double('controller')}.to raise_error "Should be defined by subclasses"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/shared_examples_for_providers'
|
3
|
+
|
4
|
+
describe OmniAuth::Provider::Facebook do
|
5
|
+
let(:controller) { double('a controller') }
|
6
|
+
subject { described_class.new controller }
|
7
|
+
|
8
|
+
it_behaves_like 'a provider'
|
9
|
+
|
10
|
+
describe '#handle_request' do
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/shared_examples_for_providers'
|
3
|
+
|
4
|
+
describe OmniAuth::Provider::Generic do
|
5
|
+
let(:controller) { double('a controller') }
|
6
|
+
subject { described_class.new controller }
|
7
|
+
|
8
|
+
it_behaves_like 'a provider'
|
9
|
+
|
10
|
+
describe '#handle_request' do
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile '~/.gitignore_global'
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore the default SQLite database.
|
11
|
+
/db/*.sqlite3
|
12
|
+
/db/*.sqlite3-journal
|
13
|
+
|
14
|
+
# Ignore all logfiles and tempfiles.
|
15
|
+
/log/*
|
16
|
+
!/log/.keep
|
17
|
+
/tmp
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require turbolinks
|
16
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|