socialite 0.0.1.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +8 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +208 -0
- data/LICENSE +176 -0
- data/README.md +63 -0
- data/Rakefile +34 -0
- data/app/assets/images/socialite/.gitkeep +0 -0
- data/app/assets/javascripts/socialite/.gitkeep +0 -0
- data/app/assets/stylesheets/socialite/socialite.css +40 -0
- data/app/assets/stylesheets/socialite.css +7 -0
- data/app/controllers/socialite/identities_controller.rb +53 -0
- data/app/controllers/socialite/session_controller.rb +28 -0
- data/app/controllers/socialite/user_controller.rb +39 -0
- data/app/helpers/socialite/authentication_helper.rb +15 -0
- data/app/models/socialite/facebook_identity.rb +7 -0
- data/app/models/socialite/identity.rb +6 -0
- data/app/models/socialite/user.rb +42 -0
- data/app/views/socialite/identities/_identities.html.haml +14 -0
- data/app/views/socialite/session/new.html.haml +14 -0
- data/app/views/socialite/user/_form.html.haml +13 -0
- data/app/views/socialite/user/edit.html.haml +1 -0
- data/app/views/socialite/user/show.html.haml +16 -0
- data/config/initializers/simple_form.rb +90 -0
- data/config/locales/simple_form.en.yml +23 -0
- data/config/routes.rb +10 -0
- data/db/migrate/20110914215410_create_users.rb +14 -0
- data/db/migrate/20110925224222_create_identities.rb +26 -0
- data/db/migrate/20110926005551_create_facebook_identities.rb +12 -0
- data/features/authentication/facebook_signin.feature +5 -0
- data/features/authentication/twitter_signin.feature +5 -0
- data/features/identities/facebook_management.feature +14 -0
- data/features/identities/twitter_management.feature +7 -0
- data/features/registration/facebook_signup.feature +10 -0
- data/features/registration/twitter_signup.feature +0 -0
- data/features/step_definitions/authentication_steps.rb +31 -0
- data/features/step_definitions/common_steps.rb +13 -0
- data/features/step_definitions/identity_steps.rb +5 -0
- data/features/step_definitions/web_steps.rb +254 -0
- data/features/support/env.rb +58 -0
- data/features/support/hooks.rb +3 -0
- data/features/support/omniauth.rb +31 -0
- data/features/support/paths.rb +34 -0
- data/features/support/selectors.rb +39 -0
- data/lib/socialite/api_wrappers/facebook.rb +67 -0
- data/lib/socialite/api_wrappers/twitter.rb +19 -0
- data/lib/socialite/base_identity.rb +96 -0
- data/lib/socialite/controller_support.rb +136 -0
- data/lib/socialite/engine.rb +32 -0
- data/lib/socialite/service_config.rb +14 -0
- data/lib/socialite/version.rb +3 -0
- data/lib/socialite.rb +37 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/socialite_tasks.rake +4 -0
- data/script/cucumber +10 -0
- data/script/rails +6 -0
- data/socialite.gemspec +39 -0
- data/spec/dummy/Rakefile +7 -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/controllers/home_controller.rb +11 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/home/index.html.haml +12 -0
- data/spec/dummy/app/views/home/show.html.haml +6 -0
- data/spec/dummy/app/views/layouts/application.html.erb +18 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/boot.rb +20 -0
- data/spec/dummy/config/database.yml +9 -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/socialite.rb +6 -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 +11 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +43 -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/script/rails +6 -0
- data/spec/factories/facebook.rb +5 -0
- data/spec/factories/identity.rb +9 -0
- data/spec/factories/twitter.rb +6 -0
- data/spec/factories/user.rb +16 -0
- data/spec/models/facebook_spec.rb +28 -0
- data/spec/models/identity_spec.rb +9 -0
- data/spec/models/user_spec.rb +27 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/.gitkeep +0 -0
- data/spec/support/database_loader.rb +13 -0
- data/spec/support/databases.yml +14 -0
- data/spec/support/identity_shared_example.rb +67 -0
- metadata +409 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Socialite
|
2
|
+
class UserController < ApplicationController
|
3
|
+
unloadable
|
4
|
+
|
5
|
+
before_filter :ensure_user
|
6
|
+
respond_to :html, :json
|
7
|
+
|
8
|
+
def show
|
9
|
+
respond_with(user)
|
10
|
+
end
|
11
|
+
|
12
|
+
def edit
|
13
|
+
respond_with(user)
|
14
|
+
end
|
15
|
+
|
16
|
+
def update
|
17
|
+
flash_message :notice, 'Your account has been removed along with any associated identities.'
|
18
|
+
respond_with(user) do |format|
|
19
|
+
format.html { redirect_back_or_default(user_path) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy
|
24
|
+
user.destroy
|
25
|
+
logout!
|
26
|
+
flash_message :notice, 'Your account has been removed along with any associated identities.'
|
27
|
+
respond_with(user) do |format|
|
28
|
+
format.html { redirect_back_or_default(user_path) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def user
|
35
|
+
@user = current_user
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Socialite
|
2
|
+
module AuthenticationHelper
|
3
|
+
def identity_request_path(options={})
|
4
|
+
[Socialite.mount_prefix, 'auth', options[:service]].join('/')
|
5
|
+
end
|
6
|
+
|
7
|
+
def twitter_login_button
|
8
|
+
content_tag(:a, content_tag(:span, 'Sign in with Twitter'), :class => 'socialite_button twitter', :href => identity_request_path(:service => 'twitter'), :rel => 'external')
|
9
|
+
end
|
10
|
+
|
11
|
+
def facebook_login_button
|
12
|
+
content_tag(:a, content_tag(:span, 'Sign in with Facebook'), :class => 'socialite_button facebook', :href => identity_request_path(:service => 'facebook'), :rel => 'external')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Socialite
|
2
|
+
class User < ActiveRecord::Base
|
3
|
+
has_many :identities, :dependent => :destroy
|
4
|
+
|
5
|
+
has_one :facebook_identity,
|
6
|
+
:class_name => 'Identity', :foreign_key => 'user_id', :conditions => { :provider => 'facebook' }
|
7
|
+
has_one :twitter_identity,
|
8
|
+
:class_name => 'Identity', :foreign_key => 'user_id', :conditions => { :provider => 'twitter' }
|
9
|
+
|
10
|
+
# Returns the first linked facebook identity
|
11
|
+
#
|
12
|
+
# @return [FacebookIdentity] the first facebook identity
|
13
|
+
def facebook
|
14
|
+
self.facebook_identity.api
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the first linked twitter account
|
18
|
+
#
|
19
|
+
# @return [TwitterIdentity] the first twitter identity
|
20
|
+
def twitter
|
21
|
+
self.twitter_identity.api
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set the user's remember token
|
25
|
+
#
|
26
|
+
# @return [User] the current user
|
27
|
+
def remember_me!
|
28
|
+
self.remember_token = Socialite.generate_token
|
29
|
+
save(:validate => false)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Clear the user's remember token
|
33
|
+
#
|
34
|
+
# @return [User] the current user
|
35
|
+
def forget_me!
|
36
|
+
if persisted?
|
37
|
+
self.remember_token = nil
|
38
|
+
save(:validate => false)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
%table
|
2
|
+
%thead
|
3
|
+
%th Provider
|
4
|
+
%th Unique ID
|
5
|
+
%th Additional
|
6
|
+
%th Actions
|
7
|
+
- identities.each do |identity|
|
8
|
+
%tr
|
9
|
+
%td= identity.provider
|
10
|
+
%td= identity.unique_id
|
11
|
+
%td= identity.auth_hash
|
12
|
+
%td
|
13
|
+
= link_to 'Unlink', user_identity_path(identity), :method => :delete, :confirm => 'Are you sure?'
|
14
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#socialite_login
|
2
|
+
.information
|
3
|
+
%h1 Sign in (or up)
|
4
|
+
%p.large
|
5
|
+
You can use either your Twitter or Facebook account to sign in or sign up.
|
6
|
+
%p
|
7
|
+
Select your preferred method and you'll be sent off to authorise us to use your account.
|
8
|
+
%p
|
9
|
+
It’ll only take a second and your information will be perfectly safe. We don't get access to your password and
|
10
|
+
%em we won't post or tweet anything from your account
|
11
|
+
without your explicit permission.
|
12
|
+
|
13
|
+
= twitter_login_button
|
14
|
+
= facebook_login_button
|
@@ -0,0 +1,13 @@
|
|
1
|
+
= simple_form_for(user) do |f|
|
2
|
+
= f.error_notification
|
3
|
+
|
4
|
+
.inputs
|
5
|
+
- user.attributes.each do |attribute|
|
6
|
+
- if attribute.reference?
|
7
|
+
= f.association attribute.name.to_sym
|
8
|
+
- else
|
9
|
+
= f.input attribute.name.to_sym
|
10
|
+
|
11
|
+
.actions
|
12
|
+
= f.button :submit
|
13
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'users/form', :locals => {:user => @user }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%h2 User Settings
|
2
|
+
|
3
|
+
- if @user.facebook_identity
|
4
|
+
%h3 Facebook Profile
|
5
|
+
= link_to 'Unlink Facebook', user_identity_path(@user.facebook_identity), :method => :delete
|
6
|
+
%section.profile.facebook
|
7
|
+
-# = @user.facebook.info
|
8
|
+
|
9
|
+
- if @user.twitter_identity
|
10
|
+
%h3 Twitter Profile
|
11
|
+
= link_to 'Unlink Twitter', user_identity_path(@user.twitter_identity), :method => :delete
|
12
|
+
%section.profile.twitter
|
13
|
+
Not Implemented Yet.
|
14
|
+
|
15
|
+
%h2 Listing Identities
|
16
|
+
= render :partial => 'socialite/identities/identities', :locals => {:identities => @user.identities.all}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'simple_form'
|
2
|
+
|
3
|
+
# Use this setup block to configure all options available in SimpleForm.
|
4
|
+
SimpleForm.setup do |config|
|
5
|
+
# Wrappers are used by the form builder to generate a complete input.
|
6
|
+
# You can remove any component from the wrapper, change the order or even
|
7
|
+
# add your own to the stack. The options given to the wrappers method
|
8
|
+
# are used to wrap the whole input (if any exists).
|
9
|
+
# config.wrappers :class => :input, :error_class => :field_with_errors do |b|
|
10
|
+
# b.use :placeholder
|
11
|
+
# b.use :label_input
|
12
|
+
# b.use :hint, :tag => :span, :class => :hint
|
13
|
+
# b.use :error, :tag => :span, :class => :error
|
14
|
+
# end
|
15
|
+
|
16
|
+
# Method used to tidy up errors.
|
17
|
+
# config.error_method = :first
|
18
|
+
|
19
|
+
# Default tag used for error notification helper.
|
20
|
+
# config.error_notification_tag = :p
|
21
|
+
|
22
|
+
# CSS class to add for error notification helper.
|
23
|
+
# config.error_notification_class = :error_notification
|
24
|
+
|
25
|
+
# ID to add for error notification helper.
|
26
|
+
# config.error_notification_id = nil
|
27
|
+
|
28
|
+
# Series of attempts to detect a default label method for collection.
|
29
|
+
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
|
30
|
+
|
31
|
+
# Series of attempts to detect a default value method for collection.
|
32
|
+
# config.collection_value_methods = [ :id, :to_s ]
|
33
|
+
|
34
|
+
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
|
35
|
+
# config.collection_wrapper_tag = nil
|
36
|
+
|
37
|
+
# You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span.
|
38
|
+
# config.item_wrapper_tag = :span
|
39
|
+
|
40
|
+
# How the label text should be generated altogether with the required text.
|
41
|
+
# config.label_text = lambda { |label, required| "#{required} #{label}" }
|
42
|
+
|
43
|
+
# You can define the class to use on all labels. Default is nil.
|
44
|
+
# config.label_class = nil
|
45
|
+
|
46
|
+
# You can define the class to use on all forms. Default is simple_form.
|
47
|
+
# config.form_class = :simple_form
|
48
|
+
|
49
|
+
# Whether attributes are required by default (or not). Default is true.
|
50
|
+
# config.required_by_default = true
|
51
|
+
|
52
|
+
# Tell browsers whether to use default HTML5 validations (novalidate option).
|
53
|
+
# Default is enabled.
|
54
|
+
# config.browser_validations = true
|
55
|
+
|
56
|
+
# Determines whether HTML5 types (:email, :url, :search, :tel) and attributes
|
57
|
+
# (e.g. required) are used or not. True by default.
|
58
|
+
# Having this on in non-HTML5 compliant sites can cause odd behavior in
|
59
|
+
# HTML5-aware browsers such as Chrome.
|
60
|
+
config.html5 = true
|
61
|
+
|
62
|
+
# Collection of methods to detect if a file type was given.
|
63
|
+
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
|
64
|
+
|
65
|
+
# Custom mappings for input types. This should be a hash containing a regexp
|
66
|
+
# to match as key, and the input type that will be used when the field name
|
67
|
+
# matches the regexp as value.
|
68
|
+
# config.input_mappings = { /count/ => :integer }
|
69
|
+
|
70
|
+
# Default priority for time_zone inputs.
|
71
|
+
# config.time_zone_priority = nil
|
72
|
+
|
73
|
+
# Default priority for country inputs.
|
74
|
+
# config.country_priority = nil
|
75
|
+
|
76
|
+
# Default size for text inputs.
|
77
|
+
# config.default_input_size = 50
|
78
|
+
|
79
|
+
# When false, do not use translations for labels, hints or placeholders.
|
80
|
+
# config.translate = true
|
81
|
+
|
82
|
+
# Automatically discover new inputs in Rails' autoload path.
|
83
|
+
# config.inputs_discovery = true
|
84
|
+
|
85
|
+
# Cache simple form inputs discovery
|
86
|
+
# config.cache_discovery = !Rails.env.development?
|
87
|
+
|
88
|
+
# Default class for buttons
|
89
|
+
# config.button_class = 'button'
|
90
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
en:
|
2
|
+
simple_form:
|
3
|
+
"yes": 'Yes'
|
4
|
+
"no": 'No'
|
5
|
+
required:
|
6
|
+
text: 'required'
|
7
|
+
mark: '*'
|
8
|
+
# You can uncomment the line below if you need to overwrite the whole required html.
|
9
|
+
# When using html, text and mark won't be used.
|
10
|
+
# html: '<abbr title="required">*</abbr>'
|
11
|
+
error_notification:
|
12
|
+
default_message: "Some errors were found, please take a look:"
|
13
|
+
# Labels and hints examples
|
14
|
+
# labels:
|
15
|
+
# password: 'Password'
|
16
|
+
# user:
|
17
|
+
# new:
|
18
|
+
# email: 'E-mail para efetuar o sign in.'
|
19
|
+
# edit:
|
20
|
+
# email: 'E-mail.'
|
21
|
+
# hints:
|
22
|
+
# username: 'User name to sign in.'
|
23
|
+
# password: 'No special characters, please.'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Socialite::Engine.routes.draw do
|
2
|
+
match '/login' => 'session#new', :as => :login
|
3
|
+
match '/auth/:service/callback' => 'identities#create', :as => :callback
|
4
|
+
match '/auth/failure' => 'identities#failure'
|
5
|
+
match '/logout' => 'session#destroy', :as => :logout
|
6
|
+
|
7
|
+
resource :user, :controller => 'user', :except => [:new, :create] do
|
8
|
+
resources :identities#, :only => [:show, :destroy]
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateIdentities < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
create_table :socialite_identities do |t|
|
4
|
+
t.belongs_to :user
|
5
|
+
t.references :api, :polymorphic => true
|
6
|
+
|
7
|
+
t.string :unique_id, :null => false
|
8
|
+
t.string :provider, :null => false
|
9
|
+
t.text :auth_hash
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :socialite_identities, :user_id
|
14
|
+
add_index :socialite_identities, [:api_id, :api_type]
|
15
|
+
add_index :socialite_identities, [:user_id, :provider], :unique => true
|
16
|
+
add_index :socialite_identities, [:provider, :unique_id], :unique => true
|
17
|
+
end
|
18
|
+
|
19
|
+
def down
|
20
|
+
remove_index :socialite_identites, :user_id
|
21
|
+
remove_index :socialite_identites, [:api_id, :api_type]
|
22
|
+
remove_index :socialite_identites, [:user_id, :provider_id]
|
23
|
+
remove_index :socialite_identites, [:provider, :unique_id]
|
24
|
+
drop_table :socialite_identities
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateFacebookIdentities < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
create_table :socialite_facebook_identities do |t|
|
4
|
+
# Additional Fields that you want to cache
|
5
|
+
t.timestamps
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def down
|
10
|
+
drop_table :socialite_facebook_identities
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@omniauth
|
2
|
+
Feature: Facebook Identity Management
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given I am authenticated with facebook
|
6
|
+
|
7
|
+
Scenario: Updating account permissions for Facebook
|
8
|
+
|
9
|
+
Scenario: Unauthorizing Facebook identity from user
|
10
|
+
When I am on the home page
|
11
|
+
And I click "User Profile"
|
12
|
+
And I click "Unlink Facebook"
|
13
|
+
Then I should not be logged in
|
14
|
+
And I should see a flash message
|
@@ -0,0 +1,10 @@
|
|
1
|
+
@omniauth
|
2
|
+
Feature: Facebook Signup
|
3
|
+
|
4
|
+
Scenario: Registration with Facebook
|
5
|
+
Given I am not authenticated
|
6
|
+
When I go to the home page
|
7
|
+
And I click "Sign in"
|
8
|
+
And I click "Sign in with Facebook"
|
9
|
+
Then I should be logged in
|
10
|
+
And I should see a flash message
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Steps related to authentication can be found below
|
2
|
+
#
|
3
|
+
Given /^I am an authenticated user$/ do
|
4
|
+
Given %{I am a user}
|
5
|
+
Given %{I am authenticated}
|
6
|
+
end
|
7
|
+
|
8
|
+
Given /^I am authenticated with facebook$/ do
|
9
|
+
Given %{I go to the home page}
|
10
|
+
And %{I click "Sign in"}
|
11
|
+
And %{I click "Sign in with Facebook"}
|
12
|
+
|
13
|
+
Then %{I should be authenticated}
|
14
|
+
And %{I should have a Facebook Identity}
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^I am not authenticated$/ do
|
18
|
+
# do nothing
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^I should (not|)\s?be (?:logged in|authenticated)$/ do |negative|
|
22
|
+
if negative.present?
|
23
|
+
# page.should_not have_content "Dashboard"
|
24
|
+
page.should_not have_content "Sign out"
|
25
|
+
page.should have_content "Sign in"
|
26
|
+
else
|
27
|
+
# page.should have_content "Dashboard"
|
28
|
+
page.should have_content "Sign out"
|
29
|
+
page.should_not have_content "Sign in"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Don't like the when I follow, so map click
|
2
|
+
# to the follow web step from capybara.
|
3
|
+
When /^(?:|I )click "([^"]*)"$/ do |button|
|
4
|
+
When %{follow "#{button}"}
|
5
|
+
end
|
6
|
+
|
7
|
+
Then /^I should (not|)\s?see a flash message$/ do |negative|
|
8
|
+
if negative.present?
|
9
|
+
page.should_not have_css "div.flash"
|
10
|
+
else
|
11
|
+
page.should have_css "div.flash"
|
12
|
+
end
|
13
|
+
end
|