socialite 0.0.1.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/.autotest +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/.yardopts +8 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +208 -0
  8. data/LICENSE +176 -0
  9. data/README.md +63 -0
  10. data/Rakefile +34 -0
  11. data/app/assets/images/socialite/.gitkeep +0 -0
  12. data/app/assets/javascripts/socialite/.gitkeep +0 -0
  13. data/app/assets/stylesheets/socialite/socialite.css +40 -0
  14. data/app/assets/stylesheets/socialite.css +7 -0
  15. data/app/controllers/socialite/identities_controller.rb +53 -0
  16. data/app/controllers/socialite/session_controller.rb +28 -0
  17. data/app/controllers/socialite/user_controller.rb +39 -0
  18. data/app/helpers/socialite/authentication_helper.rb +15 -0
  19. data/app/models/socialite/facebook_identity.rb +7 -0
  20. data/app/models/socialite/identity.rb +6 -0
  21. data/app/models/socialite/user.rb +42 -0
  22. data/app/views/socialite/identities/_identities.html.haml +14 -0
  23. data/app/views/socialite/session/new.html.haml +14 -0
  24. data/app/views/socialite/user/_form.html.haml +13 -0
  25. data/app/views/socialite/user/edit.html.haml +1 -0
  26. data/app/views/socialite/user/show.html.haml +16 -0
  27. data/config/initializers/simple_form.rb +90 -0
  28. data/config/locales/simple_form.en.yml +23 -0
  29. data/config/routes.rb +10 -0
  30. data/db/migrate/20110914215410_create_users.rb +14 -0
  31. data/db/migrate/20110925224222_create_identities.rb +26 -0
  32. data/db/migrate/20110926005551_create_facebook_identities.rb +12 -0
  33. data/features/authentication/facebook_signin.feature +5 -0
  34. data/features/authentication/twitter_signin.feature +5 -0
  35. data/features/identities/facebook_management.feature +14 -0
  36. data/features/identities/twitter_management.feature +7 -0
  37. data/features/registration/facebook_signup.feature +10 -0
  38. data/features/registration/twitter_signup.feature +0 -0
  39. data/features/step_definitions/authentication_steps.rb +31 -0
  40. data/features/step_definitions/common_steps.rb +13 -0
  41. data/features/step_definitions/identity_steps.rb +5 -0
  42. data/features/step_definitions/web_steps.rb +254 -0
  43. data/features/support/env.rb +58 -0
  44. data/features/support/hooks.rb +3 -0
  45. data/features/support/omniauth.rb +31 -0
  46. data/features/support/paths.rb +34 -0
  47. data/features/support/selectors.rb +39 -0
  48. data/lib/socialite/api_wrappers/facebook.rb +67 -0
  49. data/lib/socialite/api_wrappers/twitter.rb +19 -0
  50. data/lib/socialite/base_identity.rb +96 -0
  51. data/lib/socialite/controller_support.rb +136 -0
  52. data/lib/socialite/engine.rb +32 -0
  53. data/lib/socialite/service_config.rb +14 -0
  54. data/lib/socialite/version.rb +3 -0
  55. data/lib/socialite.rb +37 -0
  56. data/lib/tasks/.gitkeep +0 -0
  57. data/lib/tasks/cucumber.rake +65 -0
  58. data/lib/tasks/socialite_tasks.rake +4 -0
  59. data/script/cucumber +10 -0
  60. data/script/rails +6 -0
  61. data/socialite.gemspec +39 -0
  62. data/spec/dummy/Rakefile +7 -0
  63. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  64. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  65. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  66. data/spec/dummy/app/controllers/home_controller.rb +11 -0
  67. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  68. data/spec/dummy/app/views/home/index.html.haml +12 -0
  69. data/spec/dummy/app/views/home/show.html.haml +6 -0
  70. data/spec/dummy/app/views/layouts/application.html.erb +18 -0
  71. data/spec/dummy/config/application.rb +48 -0
  72. data/spec/dummy/config/boot.rb +20 -0
  73. data/spec/dummy/config/database.yml +9 -0
  74. data/spec/dummy/config/environment.rb +5 -0
  75. data/spec/dummy/config/environments/development.rb +30 -0
  76. data/spec/dummy/config/environments/production.rb +60 -0
  77. data/spec/dummy/config/environments/test.rb +42 -0
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/spec/dummy/config/initializers/inflections.rb +10 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  82. data/spec/dummy/config/initializers/session_store.rb +8 -0
  83. data/spec/dummy/config/initializers/socialite.rb +6 -0
  84. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  85. data/spec/dummy/config/locales/en.yml +5 -0
  86. data/spec/dummy/config/routes.rb +11 -0
  87. data/spec/dummy/config.ru +4 -0
  88. data/spec/dummy/db/schema.rb +43 -0
  89. data/spec/dummy/public/404.html +26 -0
  90. data/spec/dummy/public/422.html +26 -0
  91. data/spec/dummy/public/500.html +26 -0
  92. data/spec/dummy/public/favicon.ico +0 -0
  93. data/spec/dummy/script/rails +6 -0
  94. data/spec/factories/facebook.rb +5 -0
  95. data/spec/factories/identity.rb +9 -0
  96. data/spec/factories/twitter.rb +6 -0
  97. data/spec/factories/user.rb +16 -0
  98. data/spec/models/facebook_spec.rb +28 -0
  99. data/spec/models/identity_spec.rb +9 -0
  100. data/spec/models/user_spec.rb +27 -0
  101. data/spec/spec_helper.rb +29 -0
  102. data/spec/support/.gitkeep +0 -0
  103. data/spec/support/database_loader.rb +13 -0
  104. data/spec/support/databases.yml +14 -0
  105. data/spec/support/identity_shared_example.rb +67 -0
  106. 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,7 @@
1
+ module Socialite
2
+ class FacebookIdentity < ActiveRecord::Base
3
+ has_one :identity, :as => :api
4
+ delegate :access_token, :access_token_secret, :to => :identity, :allow_nil => true
5
+ include ApiWrappers::Facebook
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ module Socialite
2
+ class Identity < ActiveRecord::Base
3
+ belongs_to :api, :polymorphic => true, :dependent => :destroy
4
+ include BaseIdentity
5
+ end
6
+ 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,14 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def up
3
+ create_table :socialite_users do |t|
4
+ t.string :remember_token
5
+ # Any additional fields here
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def down
12
+ drop_table :socialite_users
13
+ end
14
+ 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,5 @@
1
+ Feature: Facebook Sign In
2
+
3
+ Scenario: Successful Sign in with Facebook Account
4
+
5
+ Scenario: Failed Sign in with Facebook Account
@@ -0,0 +1,5 @@
1
+ Feature: Twitter Sign In
2
+
3
+ Scenario: Successful sign in with Twitter
4
+
5
+ Scenario: Failed sign in with Twitter
@@ -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,7 @@
1
+ Feature: Twitter Identity Management
2
+
3
+ Scenario: Linking user to Twitter
4
+
5
+ Scenario: Unlinking user to Twitter
6
+
7
+ Scenario: Updating Twitter account permissions
@@ -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
@@ -0,0 +1,5 @@
1
+ Then /^I should have a Facebook Identity$/ do
2
+ user = Socialite::User.first
3
+ user.identities.count.should > 0
4
+ user.facebook_identity.should_not be_nil
5
+ end