billfold 1.0.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.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/README.md +39 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/app/controllers/billfold/identities_controller.rb +53 -0
- data/app/views/billfold/identities/_list.html.erb +8 -0
- data/app/views/billfold/identities/index.html.erb +2 -0
- data/billfold.gemspec +24 -0
- data/config/locales/en.yml +6 -0
- data/config/routes.rb +11 -0
- data/lib/billfold.rb +56 -0
- data/lib/billfold/active_record_identity.rb +47 -0
- data/lib/billfold/active_record_user.rb +46 -0
- data/lib/billfold/controller_support.rb +51 -0
- data/lib/billfold/engine.rb +25 -0
- data/lib/billfold/identity.rb +99 -0
- data/lib/billfold/user.rb +25 -0
- data/lib/rails/generators/billfold/migration_generator.rb +27 -0
- data/lib/rails/generators/billfold/models_generator.rb +14 -0
- data/lib/rails/generators/billfold/templates/identity.rb +5 -0
- data/lib/rails/generators/billfold/templates/migration.rb +23 -0
- data/lib/rails/generators/billfold/templates/user.rb +5 -0
- data/spec/billfold_spec.rb +23 -0
- data/spec/controllers/identities_controller_spec.rb +31 -0
- data/spec/dummy/.gitignore +5 -0
- data/spec/dummy/README +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/identity.rb +5 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +30 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/migrate/20110904204023_create_users_and_identities.rb +23 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/doc/README_FOR_APP +2 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/tasks/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html +241 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/test/fixtures/.gitkeep +0 -0
- data/spec/dummy/test/functional/.gitkeep +0 -0
- data/spec/dummy/test/integration/.gitkeep +0 -0
- data/spec/dummy/test/performance/browsing_test.rb +12 -0
- data/spec/dummy/test/test_helper.rb +13 -0
- data/spec/dummy/test/unit/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/dummy/vendor/plugins/.gitkeep +0 -0
- data/spec/factories/identity_factories.rb +18 -0
- data/spec/factories/user_factories.rb +7 -0
- data/spec/models/identity_spec.rb +123 -0
- data/spec/spec_helper.rb +30 -0
- metadata +260 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
## Billfold
|
2
|
+
|
3
|
+
Billfold provides backend Rails support for OmniAuth. Specifically, it
|
4
|
+
routes `/auth/:provider/callback` to
|
5
|
+
`Billfold::IdentitiesController#update_or_create!`, which handles
|
6
|
+
identity management.
|
7
|
+
|
8
|
+
### Requirements
|
9
|
+
|
10
|
+
* Rails 3.x
|
11
|
+
|
12
|
+
### Installation
|
13
|
+
|
14
|
+
1. Add `gem 'billfold'` to your `Gemfile`
|
15
|
+
1. Run `bundle` (or `bundle install`)
|
16
|
+
1. Run `rails g billfold:migration`
|
17
|
+
|
18
|
+
### Configuration
|
19
|
+
|
20
|
+
#### With ActiveRecord
|
21
|
+
|
22
|
+
If you don't have User and Identity model classes, run
|
23
|
+
`rails g billfold:models` to create them. Otherwise, include
|
24
|
+
`Billfold::ActiveRecordUser` and `Billfold::ActiveRecordIdentity` in
|
25
|
+
them respectively. You *may* wish to define
|
26
|
+
`User#perform_additional_merge_operations!` if you need to do additional
|
27
|
+
logic during a user merge.
|
28
|
+
|
29
|
+
#### Without ActiveRecord
|
30
|
+
|
31
|
+
Include `Billfold::User` and `Billfold::Identity` in the model classes.
|
32
|
+
You'll also have do define the following methods:
|
33
|
+
|
34
|
+
* `User.find_by_id(id)`
|
35
|
+
* `User#merge_into!(other_user)`
|
36
|
+
* `Identity.with_provider_and_value(provider, value)`
|
37
|
+
* `Identity#user`
|
38
|
+
* `Identity#update_attributes!`
|
39
|
+
* `Identity#save!`
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'rubygems'
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rdoc/task'
|
11
|
+
|
12
|
+
require 'rspec/core'
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
RSpec::Core::RakeTask.new(:spec)
|
15
|
+
|
16
|
+
desc "Default: run the unit tests."
|
17
|
+
task :default => [:spec]
|
18
|
+
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = "Billfold #{File.read './VERSION'}"
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README.rdoc')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
rdoc.rdoc_files.include('app/**/*.rb')
|
26
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Billfold
|
2
|
+
class IdentitiesController < ApplicationController
|
3
|
+
|
4
|
+
before_filter :require_sign_in, :only => [ :index, :destroy ]
|
5
|
+
|
6
|
+
respond_to :html, :json, :xml
|
7
|
+
helper_method :identities, :identity
|
8
|
+
|
9
|
+
def index
|
10
|
+
respond_to do |format|
|
11
|
+
format.html {}
|
12
|
+
format.json { render :json => identities }
|
13
|
+
format.xml { render :xml => identities }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_or_create
|
18
|
+
omniauth_hash = request.env['omniauth.auth'] || {}
|
19
|
+
identity = Billfold.identity_class.update_or_create!({
|
20
|
+
:provider => params[:provider],
|
21
|
+
:value => omniauth_hash['uid'],
|
22
|
+
:data => omniauth_hash['user_info'],
|
23
|
+
:user => current_user
|
24
|
+
})
|
25
|
+
self.current_user ||= identity.user
|
26
|
+
respond_to do |format|
|
27
|
+
format.html { redirect_to '/' }
|
28
|
+
format.json { head 201 }
|
29
|
+
format.xml { head 201 }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
identity.destroy
|
35
|
+
respond_to do |format|
|
36
|
+
format.html { redirect_to :index }
|
37
|
+
format.json { head 200 }
|
38
|
+
format.xml { head 200 }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def identities
|
45
|
+
@identities ||= current_user.identities
|
46
|
+
end
|
47
|
+
|
48
|
+
def identity
|
49
|
+
@identity ||= current_user.identities.find_by_id(params[:identity_id] || params[:id])
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/billfold.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'billfold'
|
5
|
+
gem.version = File.read('VERSION')
|
6
|
+
gem.description = %q{Identity Management with OmniAuth}
|
7
|
+
gem.summary = gem.description
|
8
|
+
gem.email = ['james.a.rosen@gmail.com']
|
9
|
+
gem.homepage = 'http://github.com/jamesarosen/billfold'
|
10
|
+
gem.authors = ['James A. Rosen']
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.require_paths = ['lib']
|
15
|
+
gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if gem.respond_to? :required_rubygems_version=
|
16
|
+
|
17
|
+
gem.add_development_dependency 'rails', '~> 3.1'
|
18
|
+
gem.add_development_dependency 'bundler'
|
19
|
+
gem.add_development_dependency 'mocha'
|
20
|
+
gem.add_development_dependency 'rake'
|
21
|
+
gem.add_development_dependency 'rspec-rails'
|
22
|
+
gem.add_development_dependency 'sqlite3'
|
23
|
+
gem.add_development_dependency 'factory_girl'
|
24
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
|
3
|
+
mount_at = Billfold::Engine.config.mount_at
|
4
|
+
|
5
|
+
post "#{mount_at}auth/:provider/callback" => 'billfold/identities#update_or_create'
|
6
|
+
|
7
|
+
resources :identities, :only => [ :index, :destroy ],
|
8
|
+
:module => 'billfold',
|
9
|
+
:path => "#{mount_at}/identities"
|
10
|
+
|
11
|
+
end
|
data/lib/billfold.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Billfold
|
2
|
+
|
3
|
+
autoload :ControllerSupport, 'billfold/controller_support'
|
4
|
+
autoload :Identity, 'billfold/identity'
|
5
|
+
autoload :User, 'billfold/user'
|
6
|
+
autoload :ActiveRecordIdentity, 'billfold/active_record_identity'
|
7
|
+
autoload :ActiveRecordUser, 'billfold/active_record_user'
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
# ## Billfold.user_class
|
11
|
+
#
|
12
|
+
# Used by `Billfold::Identity.update_or_create!` when building new users
|
13
|
+
# and `Billfold::ControllerSupport` when looking up the current user
|
14
|
+
# from the session. Calculated from `Billfold.user_class_name`.
|
15
|
+
def user_class
|
16
|
+
constantize user_class_name
|
17
|
+
end
|
18
|
+
|
19
|
+
# Used by `Billfold::ActiveRecordIdentity` for the `belongs_to :user`
|
20
|
+
# association and by `Billfold.user_class` for getting the actual
|
21
|
+
# class. By default, "User"
|
22
|
+
def user_class_name
|
23
|
+
@user_class ||= 'User'
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_writer :user_class_name
|
27
|
+
|
28
|
+
# ## Billfold.identity_class
|
29
|
+
#
|
30
|
+
# Used by `Billfold::IdentitiesController.update_or_create`. Calculated
|
31
|
+
# from `Billfold.identity_class_name`.
|
32
|
+
def identity_class
|
33
|
+
constantize identity_class_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def identity_class_name
|
37
|
+
@identity_class ||= 'Identity'
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_writer :identity_class_name
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def constantize(string)
|
45
|
+
return nil if string.blank?
|
46
|
+
return string.constantize if string.respond_to?(:constantize)
|
47
|
+
string.to_s.split('::').inject(Object) do |memo, name|
|
48
|
+
raise "#{memo}::#{name} does not exist" unless memo.const_defined?(name)
|
49
|
+
memo = memo.const_get(name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require 'billfold/identity'
|
55
|
+
require 'billfold/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
56
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'billfold/identity'
|
3
|
+
|
4
|
+
module Billfold
|
5
|
+
|
6
|
+
# ## Billfold::ActiveRecordIdentity
|
7
|
+
#
|
8
|
+
# Support for an ActiveRecord Identity class. (Builds on top of
|
9
|
+
# `Billfold::Identity`)
|
10
|
+
module ActiveRecordIdentity
|
11
|
+
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do
|
15
|
+
raise "Cannot define identity class until Billfold.user_class_name is set" unless Billfold.user_class_name.present?
|
16
|
+
belongs_to :user, :class_name => ::Billfold.user_class_name
|
17
|
+
serialize :data
|
18
|
+
validates_presence_of :user, :provider, :value
|
19
|
+
|
20
|
+
# There can only be one identity with a given provider and value
|
21
|
+
validates_uniqueness_of :value, :scope => [ :provider ]
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
include Billfold::Identity::ClassMethods
|
27
|
+
|
28
|
+
# ### Billfold::Identity.with_provider_and_value
|
29
|
+
#
|
30
|
+
# Return the identity with the given `provider` and `value`, or `nil`,
|
31
|
+
# if no such identity exists. Including classes *must* redefine this
|
32
|
+
# method.
|
33
|
+
def with_provider_and_value(provider, value)
|
34
|
+
where(:provider => provider, :value => value).first
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
|
41
|
+
include Billfold::Identity::InstanceMethods
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'billfold/user'
|
3
|
+
|
4
|
+
module Billfold
|
5
|
+
|
6
|
+
# ## Billfold::ActiveRecordUser
|
7
|
+
#
|
8
|
+
# Support for an ActiveRecord User class. (Builds on top of
|
9
|
+
# `Billfold::User`)
|
10
|
+
module ActiveRecordUser
|
11
|
+
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do
|
15
|
+
raise "Cannot define user class until Billfold.identity_class_name is set" unless Billfold.identity_class_name.present?
|
16
|
+
validates_presence_of :name
|
17
|
+
has_many :identities, :class_name => ::Billfold.identity_class_name
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
# Merge this user into another user, deleting this user and moving its
|
23
|
+
# identities to the other.
|
24
|
+
def merge_into!(other)
|
25
|
+
raise ArgumentError.new("#{other} is not a #{Billfold.user_class}") unless other.kind_of?(Billfold.user_class)
|
26
|
+
raise ArgumentError.new("#{other} is not saved") if other.new_record?
|
27
|
+
transaction do
|
28
|
+
identities.update_all({ :user_id => other.id })
|
29
|
+
perform_additional_merge_operations!(other)
|
30
|
+
destroy
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# This method is called after all identities have been moved from
|
37
|
+
# `other` to `self`, but before `other` has been destroyed and before the
|
38
|
+
# end of the transaction. By default, it does nothing.
|
39
|
+
def perform_additional_merge_operations!(other)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'billfold'
|
3
|
+
|
4
|
+
module Billfold
|
5
|
+
|
6
|
+
# ## Billfold::ControllerSupport
|
7
|
+
#
|
8
|
+
# Gets mixed in to `ApplicationController` automatically.
|
9
|
+
module ControllerSupport
|
10
|
+
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
helper_method :current_user
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# ### Billfold::ControllerSupport#current_user
|
22
|
+
#
|
23
|
+
# Return the current user, if signed in.
|
24
|
+
def current_user
|
25
|
+
@current_user ||= ::Billfold::user_class.find_by_id(session[:user_id])
|
26
|
+
end
|
27
|
+
|
28
|
+
# ### Billfold::ControllerSupport#current_user=
|
29
|
+
#
|
30
|
+
# Set the signed-in user.
|
31
|
+
def current_user=(user)
|
32
|
+
session[:user_id] = user ? user.id : nil
|
33
|
+
@current_user = user
|
34
|
+
end
|
35
|
+
|
36
|
+
# ### Billfold::ControllerSupport#require_sign_in
|
37
|
+
#
|
38
|
+
# A before filter that requires a user to be signed in. The default
|
39
|
+
# implementation adds a flash message and redirects to /
|
40
|
+
def require_sign_in
|
41
|
+
unless current_user
|
42
|
+
flash['info'] = 'Please sign in'
|
43
|
+
redirect_to root_path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'billfold'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module Billfold
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
engine_name :my_rails_engine
|
7
|
+
|
8
|
+
# Config defaults
|
9
|
+
config.mount_at = '/'
|
10
|
+
|
11
|
+
# Check the gem config
|
12
|
+
initializer "check config" do |app|
|
13
|
+
# make sure mount_at ends with trailing slash
|
14
|
+
config.mount_at += '/' unless config.mount_at.last == '/'
|
15
|
+
end
|
16
|
+
|
17
|
+
initializer "static assets" do |app|
|
18
|
+
app.middleware.use ::ActionDispatch::Static, "#{root}/public"
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveSupport.on_load(:action_controller) do
|
22
|
+
include Billfold::ControllerSupport
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'billfold'
|
2
|
+
|
3
|
+
module Billfold
|
4
|
+
|
5
|
+
# ## Billfold::Identity
|
6
|
+
#
|
7
|
+
# Support for an identity class. If you are using ActiveRecord, you
|
8
|
+
# probably want `Billfold::ActiveRecordIdentity`, which includes everything
|
9
|
+
# in this module.
|
10
|
+
#
|
11
|
+
# Requires the following attributes
|
12
|
+
# * `user` -- the owning `Billfold::User` instance; required
|
13
|
+
# * `provider` -- the OmniAuth provider name (e.g. "twitter"); required
|
14
|
+
# * `value` -- the unique identifier (within the scope of `provider`) of
|
15
|
+
# the identity (e.g. "my_twitter_handle"); required
|
16
|
+
# * `data` -- additional information passed in from OmniAuth under the
|
17
|
+
# `"user_info"` key
|
18
|
+
module Identity
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.extend ClassMethods
|
22
|
+
base.send(:include, InstanceMethods)
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
|
27
|
+
# ### Billfold::Identity.with_provider_and_value
|
28
|
+
#
|
29
|
+
# Return the identity with the given `provider` and `value`, or `nil`,
|
30
|
+
# if no such identity exists. Including classes *must* redefine this
|
31
|
+
# method.
|
32
|
+
def with_provider_and_value(provider, value)
|
33
|
+
raise NotImplementedError.new('classes including Billfold::Identity MUST redefine class method with_provider_and_value')
|
34
|
+
end
|
35
|
+
|
36
|
+
# ### Billfold::Identity.update_or_create!
|
37
|
+
#
|
38
|
+
# Updates or creates a `Billfold::Identity`.
|
39
|
+
#
|
40
|
+
# ### Parameters: a single `Hash` with the following keys:
|
41
|
+
# * `:provider` -- the name of an OmniAuth provider (e.g. "twitter")
|
42
|
+
# * `:user` -- if nil, creates a new `User` for the `Identity`
|
43
|
+
# * `:value` -- the unique identifier
|
44
|
+
# * `:data` -- extra data for the Identity
|
45
|
+
#
|
46
|
+
# ### Behavior
|
47
|
+
#
|
48
|
+
# If `:provider` or `:value` is `nil`, this method raises an
|
49
|
+
# `ArgumentError`.
|
50
|
+
#
|
51
|
+
# If `:user` is `nil`, this method creates a new `User` for the `Identity`.
|
52
|
+
#
|
53
|
+
# If `:user` exists and there is no other `Identity` with the
|
54
|
+
# same `:value`, this method adds a new `Identity` to the `User`.
|
55
|
+
#
|
56
|
+
# If there exists another `Identity` with the same `:value` and
|
57
|
+
# that `Identity` is owned by the given `User`, this method updates that
|
58
|
+
# `Identity`.
|
59
|
+
#
|
60
|
+
# If `:user` exists and there exists another `Identity` with
|
61
|
+
# the same `:value` and that `Identity` is owned by a *different* `User`,
|
62
|
+
# this method merges that User into `:user` and updates the `Identity`.
|
63
|
+
def update_or_create!(attributes = {})
|
64
|
+
raise ArgumentError.new("provider must not be blank") if attributes[:provider].blank?
|
65
|
+
raise ArgumentError.new("value must not be blank") if attributes[:value].blank?
|
66
|
+
identity = with_provider_and_value(attributes[:provider], attributes[:value])
|
67
|
+
if identity
|
68
|
+
old_owner, new_owner = identity.user, attributes[:user]
|
69
|
+
transaction do
|
70
|
+
identity.update_attributes!(attributes)
|
71
|
+
old_owner.merge_into!(new_owner) if old_owner != new_owner
|
72
|
+
end
|
73
|
+
else
|
74
|
+
identity = new(attributes)
|
75
|
+
identity.user = attributes[:user] || ::Billfold.user_class.new(:name => identity.name_for_user)
|
76
|
+
identity.save!
|
77
|
+
end
|
78
|
+
identity
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
module InstanceMethods
|
84
|
+
|
85
|
+
# ### Billfold::Identity#name_for_user
|
86
|
+
#
|
87
|
+
# When creating a new user from an identity, this method is used to
|
88
|
+
# generate a display name. By default, it tries to get the user's name
|
89
|
+
# from the OmniAuth data and falls back on using the identity's provider
|
90
|
+
# and value, but subclasses may have something better to do.
|
91
|
+
def name_for_user
|
92
|
+
(data && data['name']) || "#{provider} #{value}"
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|