socialite 0.0.1.beta

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.
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