socialite 0.1.0.pre → 0.1.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/app/assets/images/socialite/facebook_64.png +0 -0
  2. data/app/assets/images/socialite/twitter_64.png +0 -0
  3. data/app/controllers/socialite/sessions_controller.rb +69 -0
  4. data/app/controllers/socialite/users_controller.rb +2 -31
  5. data/app/views/layouts/socialite/application.html.haml +1 -1
  6. data/app/views/socialite/identities/new.html.haml +6 -19
  7. data/app/views/socialite/sessions/new.html.haml +30 -0
  8. data/app/views/socialite/users/new.html.haml +10 -0
  9. data/config/routes.rb +6 -7
  10. data/lib/generators/socialite/install_generator.rb +24 -5
  11. data/lib/generators/socialite/migrations_generator.rb +1 -1
  12. data/lib/generators/socialite/templates/socialite.rb +9 -0
  13. data/lib/generators/socialite/templates/users.rb.erb +5 -1
  14. data/lib/generators/socialite/views_generator.rb +22 -0
  15. data/lib/socialite.rb +4 -8
  16. data/lib/socialite/controllers/helpers.rb +5 -115
  17. data/lib/socialite/engine.rb +8 -11
  18. data/lib/socialite/ext/omniauth/identity/model.rb +29 -0
  19. data/lib/socialite/models/identity_concern.rb +24 -5
  20. data/lib/socialite/models/user_concern.rb +39 -0
  21. data/lib/socialite/version.rb +1 -1
  22. data/spec/dummy/app/controllers/pages_controller.rb +7 -0
  23. data/spec/dummy/app/models/user.rb +2 -0
  24. data/spec/dummy/app/views/pages/index.html.haml +5 -0
  25. data/spec/dummy/config/initializers/omniauth-identity.rb +11 -0
  26. data/spec/dummy/config/initializers/socialite.rb +9 -0
  27. data/spec/dummy/config/routes.rb +17 -1
  28. data/spec/dummy/db/migrate/20130207223009_create_socialite_users.rb +16 -0
  29. data/spec/dummy/db/migrate/{20130206224517_create_socialite_identities.rb → 20130207223010_create_socialite_identities.rb} +0 -0
  30. data/spec/dummy/db/schema.rb +7 -3
  31. data/spec/factories/user.rb +11 -1
  32. data/{features/registration/twitter_signup.feature → spec/features/.gitkeep} +0 -0
  33. data/spec/features/facebook_registration_spec.rb +16 -0
  34. data/spec/features/identity_login_spec.rb +26 -0
  35. data/spec/features/identity_registration_spec.rb +31 -0
  36. data/spec/generators/socialite/install_generator_spec.rb +8 -1
  37. data/spec/generators/socialite/views_generator_spec.rb +27 -0
  38. data/spec/models/identity_spec.rb +4 -6
  39. data/spec/models/user_spec.rb +18 -18
  40. data/spec/socialite_spec.rb +31 -7
  41. data/spec/spec_helper.rb +4 -1
  42. data/spec/support/capybara.rb +3 -0
  43. data/spec/support/database_cleaner.rb +18 -0
  44. data/spec/support/identity_shared_example.rb +4 -23
  45. data/spec/support/omniauth.rb +35 -0
  46. metadata +95 -78
  47. data/app/controllers/socialite/identities_controller.rb +0 -41
  48. data/app/controllers/socialite/session_controller.rb +0 -32
  49. data/app/views/socialite/session/new.html.haml +0 -31
  50. data/app/views/socialite/user/_form.html.haml +0 -13
  51. data/app/views/socialite/user/edit.html.haml +0 -1
  52. data/app/views/socialite/user/show.html.haml +0 -16
  53. data/features/authentication/facebook_signin.feature +0 -5
  54. data/features/authentication/twitter_signin.feature +0 -5
  55. data/features/identities/facebook_management.feature +0 -14
  56. data/features/identities/twitter_management.feature +0 -7
  57. data/features/registration/facebook_signup.feature +0 -10
  58. data/features/step_definitions/authentication_steps.rb +0 -31
  59. data/features/step_definitions/common_steps.rb +0 -13
  60. data/features/step_definitions/identity_steps.rb +0 -5
  61. data/features/step_definitions/web_steps.rb +0 -254
  62. data/features/support/env.rb +0 -58
  63. data/features/support/hooks.rb +0 -3
  64. data/features/support/omniauth.rb +0 -31
  65. data/features/support/paths.rb +0 -34
  66. data/features/support/selectors.rb +0 -39
  67. data/lib/socialite/helpers/authentication.rb +0 -17
  68. data/lib/socialite/models/facebook_identity.rb +0 -14
  69. data/spec/dummy/db/migrate/20130206224516_create_socialite_users.rb +0 -12
  70. data/spec/factories/facebook.rb +0 -5
  71. data/spec/factories/twitter.rb +0 -6
  72. data/spec/models/facebook_spec.rb +0 -31
@@ -0,0 +1,69 @@
1
+ module Socialite
2
+ class SessionsController < ApplicationController
3
+ unloadable
4
+
5
+ def new
6
+ # Login Page
7
+ end
8
+
9
+ def create
10
+ auth = request.env['omniauth.auth']
11
+ # Find an identity here
12
+ @identity = Socialite.identity_class.find_or_create_from_omniauth(auth)
13
+
14
+ if user_signed_in? # Check if user is already signed in.
15
+ if @identity.user == current_user
16
+ # User is signed in so they are trying to link an identity with their
17
+ # account. But we found the identity and the user associated with it
18
+ # is the current user. So the identity is already associated with
19
+ # this user. So let's display an error message.
20
+ redirect_to main_app.root_url, :notice => "You have already linked this account"
21
+ else
22
+ # The identity is not associated with the current_user so lets
23
+ # associate the identity.
24
+ @identity.user = current_user
25
+ @identity.save
26
+ redirect_to main_app.root_url, :notice => "Account successfully authenticated"
27
+ end
28
+ else # User is not logged in, this is a new signin
29
+ if @identity.user.present?
30
+ # The identity we found had a user associated with it so let's
31
+ # just log them in here
32
+ self.current_user = @identity.user
33
+ redirect_to main_app.root_url, :notice => "Signed in!"
34
+ else
35
+ # The authentication has no user assigned and there is no user signed in
36
+ # Our decision here is to create a new account for the user
37
+ # But your app may do something different (eg. ask the user
38
+ # if he already signed up with some other service)
39
+ user = if @identity.provider == 'identity'
40
+ Socialite.user_class.find(@identity.uid)
41
+ # If the provider is identity, then it means we already created a user
42
+ # So we just load it up
43
+ else
44
+ # otherwise we have to create a user with the auth hash
45
+ Socialite.user_class.create_from_omniauth(auth)
46
+ # NOTE: we will handle the different types of data we get back
47
+ # from providers at the model level in create_from_omniauth
48
+ end
49
+ # We can now link the authentication with the user and log him in
50
+ user.identities << @identity
51
+ self.current_user = user
52
+ redirect_to main_app.root_path, notice: "Welcome to The app!"
53
+
54
+ # No user associated with the identity so we need to create a new one
55
+ # redirect_to new_user_url, :notice => "Please finish registering"
56
+ end
57
+ end
58
+ end
59
+
60
+ def destroy
61
+ self.current_user = nil
62
+ redirect_to main_app.root_url, :notice => 'Signed out!'
63
+ end
64
+
65
+ def failure
66
+ redirect_to main_app.root_url, :alert => "Authentication failed, please try again."
67
+ end
68
+ end
69
+ end
@@ -2,37 +2,8 @@ module Socialite
2
2
  class UsersController < ApplicationController
3
3
  unloadable
4
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
5
+ def new
6
+ @user = env['omniauth.identity'] ||= Socialite.user_class.new
36
7
  end
37
8
  end
38
9
  end
@@ -2,7 +2,7 @@
2
2
  %html
3
3
  %head
4
4
  %title Socialite
5
- = stylesheet_link_tag "socialite/application", :media => "all"
5
+ = stylesheet_link_tag "socialite/application", :media => "all"
6
6
  = javascript_include_tag "socialite/application"
7
7
  = csrf_meta_tags
8
8
  %body
@@ -1,27 +1,14 @@
1
1
  %h1 New Account
2
2
 
3
- = form_tag "/auth/identity/register" do
3
+ = simple_form_for @identity, :url => '/auth/identity/register' do |f|
4
4
  - if @identity && @identity.errors.any?
5
5
  .error_messages
6
6
  %h2 #{pluralize(@identity.errors.count, "error")} prohibited this account from being saved:
7
7
  %ul
8
8
  - @identity.errors.full_messages.each do |msg|
9
9
  %li= msg
10
- .field
11
- = label_tag :name
12
- %br
13
- = text_field_tag :name, @identity.try(:name)
14
- .field
15
- = label_tag :email
16
- %br
17
- = text_field_tag :email, @identity.try(:email)
18
- .field
19
- = label_tag :password
20
- %br
21
- = password_field_tag :password
22
- .field
23
- = label_tag :password_confirmation
24
- %br
25
- = password_field_tag :password_confirmation
26
- .actions
27
- = submit_tag "Register"
10
+
11
+ = f.input :email, :input_html => {:name => 'email'}
12
+ = f.input :password, :as => 'password', :input_html => {:name => 'password'}
13
+ = f.input :password_confirmation, :label => "Confirm Password", :as => 'password', :input_html => {:name => 'password_confirmation'}
14
+ = f.button :submit, 'Register'
@@ -0,0 +1,30 @@
1
+ %h1 Sign In
2
+
3
+ %p
4
+ %strong Sign in through one of these services:
5
+
6
+ .auth_providers
7
+ - if defined?(OmniAuth::Strategies::Twitter)
8
+ %a.auth_provider{:href => "/auth/twitter"}
9
+ = image_tag "twitter_64.png", :size => "64x64", :alt => "Twitter"
10
+ Twitter
11
+ - if defined?(OmniAuth::Strategies::Facebook)
12
+ %a.auth_provider{:href => "/auth/facebook"}
13
+ = image_tag "facebook_64.png", :size => "64x64", :alt => "Facebook"
14
+ Facebook
15
+
16
+ %p
17
+ %strong Don't use these services?
18
+ #{link_to "Create an account", signup_path} or login below.
19
+
20
+ = form_tag "/auth/identity/callback" do
21
+ .field
22
+ = label_tag :auth_key, "Email"
23
+ %br
24
+ = text_field_tag :auth_key
25
+ .field
26
+ = label_tag :password
27
+ %br
28
+ = password_field_tag :password
29
+ .actions
30
+ = submit_tag "Sign in"
@@ -0,0 +1,10 @@
1
+ -# UsersController#new registration form is ONLY used with omniauth-identity
2
+
3
+ = simple_form_for @user, :url => '/auth/identity/register' do |f|
4
+ %h1 Create an Account
5
+ -# specify :input_html to avoid params nesting
6
+ -# = f.input :name, :input_html => {:name => 'name'}
7
+ = f.input :email, :input_html => {:name => 'email'}
8
+ = f.input :password, :as => 'password', :input_html => {:name => 'password'}
9
+ = f.input :password_confirmation, :label => "Confirm Password", :as => 'password', :input_html => {:name => 'password_confirmation'}
10
+ = f.button :submit, 'Sign Up'
@@ -1,10 +1,9 @@
1
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
2
+ match '/signup', :to => 'users#new'
3
+ match '/auth/:provider/callback', :to => 'sessions#create'
6
4
 
7
- # resource :user, :except => [:new, :create] do
8
- # resources :identities
9
- # end
5
+ match '/logout', :to => 'sessions#destroy', :as => 'logout'
6
+ match '/login', :to => 'sessions#new', :as => 'login'
7
+
8
+ resources :users # needed by omniauth-identity
10
9
  end
@@ -2,7 +2,7 @@ require 'rails/generators'
2
2
 
3
3
  module Socialite
4
4
  module Generators
5
- class InstallGenerator < ::Rails::Generators::Base
5
+ class InstallGenerator < ::Rails::Generators::Base #:nodoc:
6
6
  source_root File.expand_path("../templates", __FILE__)
7
7
 
8
8
  desc 'Creates a socialite initializer'
@@ -10,10 +10,29 @@ module Socialite
10
10
  template 'socialite.rb', 'config/initializers/socialite.rb'
11
11
  end
12
12
 
13
- # def add_opro_routes
14
- # socialite_routes = "mount_socialite_oauth"
15
- # route socialite_routes
16
- # end
13
+ def mount_engine
14
+ puts "Mounting Socialite::Engine at \"/socialite\" in config/routes.rb..."
15
+ insert_into_file("config/routes.rb", :after => /routes.draw.do\n/) do
16
+ %Q{
17
+ # This line mounts Socialite's routes at /socialite by default.
18
+ # This means, any requests to the /socialite URL of your application will go
19
+ # to Socialite::SessionsController#new. If you would like to change where
20
+ # this extension is mounted, simply change the :at option to something
21
+ # different.
22
+ #
23
+ # We ask that you don't use the :as option here, as Socialite relies on it
24
+ # being the default of "socialite"
25
+ mount Socialite::Engine, :at => '/socialite'
26
+ match '/login' => 'socialite::sessions#new'
27
+ match '/logout', :to => 'socialite::sessions#destroy'
28
+ match '/signup', :to => 'socialite::users#new'
29
+ match '/auth/:provider/callback', :to => 'socialite::sessions#create'
30
+ match '/auth/failure', :to => 'socialite::sessions#failure'
31
+
32
+ }
33
+ end
34
+
35
+ end
17
36
  end
18
37
  end
19
38
  end
@@ -2,7 +2,7 @@ require 'rails/generators/migration'
2
2
 
3
3
  module Socialite
4
4
  module Generators
5
- class MigrationsGenerator < ::Rails::Generators::Base
5
+ class MigrationsGenerator < ::Rails::Generators::Base #:nodoc:
6
6
  include Rails::Generators::Migration
7
7
  source_root File.expand_path('../templates', __FILE__)
8
8
 
@@ -20,6 +20,15 @@ Socialite.setup do |config|
20
20
  # }
21
21
  # config.provider :twitter, ENV['TWITTER_APP_KEY'], ENV['TWITTER_SECRET']
22
22
 
23
+ # We highly recommended adding the omniauth-identity gem to your Gemfile.
24
+ # This does not enforce a password on signup, but establishes a common
25
+ # 'password recovery' entry point for all users.
26
+ #
27
+ # config.provider :identity,
28
+ # :model => Socialite.user_class,
29
+ # :fields => [:email],
30
+ # :on_failed_registration => Socialite::UsersController.action(:new)
31
+
23
32
  if Rails.env.production?
24
33
  # Any production specific information
25
34
  elsif Rails.env.development?
@@ -1,9 +1,13 @@
1
1
  class CreateSocialiteUsers < ActiveRecord::Migration
2
2
  def up
3
3
  create_table :<%= options[:users_table] %> do |t|
4
- t.string :name
4
+ t.string :name, :email
5
+ t.string :password_digest # set :null => false to enforce identity, requires 'bcrypt-ruby' in your Gemfile.
5
6
  t.timestamps
6
7
  end
8
+
9
+ # Enforce only every email must be unique
10
+ add_index :<%= options[:users_table] %>, :email, :unique => true
7
11
  end
8
12
 
9
13
  def down
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+
3
+ module Socialite
4
+ module Generators
5
+ class ViewsGenerator < ::Rails::Generators::Base #:nodoc:
6
+ source_root File.expand_path("../../../../app/views/socialite", __FILE__)
7
+ desc "Used to copy socialite's views to your application's views."
8
+
9
+ def copy_views
10
+ view_directory :identities
11
+ view_directory :sessions
12
+ view_directory :users
13
+ end
14
+
15
+ protected
16
+
17
+ def view_directory(name)
18
+ directory name.to_s, "app/views/socialite/#{name}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -10,10 +10,6 @@ module Socialite
10
10
  autoload :Helpers, 'socialite/controllers/helpers'
11
11
  end
12
12
 
13
- module Helpers
14
- autoload :Authentication, 'socialite/helpers/authentication.rb'
15
- end
16
-
17
13
  module Models
18
14
  autoload :IdentityConcern, 'socialite/models/identity_concern'
19
15
  autoload :UserConcern, 'socialite/models/user_concern'
@@ -35,18 +31,18 @@ module Socialite
35
31
  end
36
32
 
37
33
  def self.identity_class
38
- identity_class_name.constantize
34
+ identity_class_name.try(:constantize)
39
35
  end
40
36
 
41
37
  def self.identity_class_name
42
- @@identity_class.camelize
38
+ @@identity_class.try(:camelize) || 'Identity'
43
39
  end
44
40
 
45
41
  def self.user_class
46
- user_class_name.constantize
42
+ user_class_name.try(:constantize)
47
43
  end
48
44
 
49
45
  def self.user_class_name
50
- @@user_class.camelize
46
+ @@user_class.try(:camelize) || 'User'
51
47
  end
52
48
  end
@@ -4,130 +4,20 @@ module Socialite
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- helper_method :current_user, :user_signed_in?, :current_user?, :default_route
7
+ helper_method :current_user, :user_signed_in?
8
8
  end
9
9
 
10
- # Set default route for redirect
11
- #
12
- # @param [String] the path for default redirects
13
- # @return [String] the default path for redirect
14
- # (see #default_route)
15
- def default_route=(route)
16
- @default_route = route
17
- end
18
-
19
- # Get default route for redirect
20
- #
21
- # @return [String] the default path for redirect
22
- # (see #default_route=)
23
- def default_route
24
- @default_route ||= main_app.root_url
25
- end
26
-
27
- # Helper for supporting multiple flash messages per type
28
- #
29
- # @param [Symbol] the type of flash message. Common types are
30
- # :success, :notice, :error
31
- # @param [String] the message to attach to the flash type
32
- # @return [Hash] all associated flash messages for this request
33
- def flash_message(type, text)
34
- flash[type.to_sym] ||= []
35
- flash[type.to_sym] << text
36
- end
37
-
38
- protected
39
-
40
- # Filters
41
-
42
- # Conditional check to see ensure a current user exists
43
- #
44
- # @return [Boolean]
45
- # (see #current_user?)
46
- def ensure_user
47
- current_user? || deny_access('You must be logged in to perform this action.')
48
- end
49
-
50
- # Conditional check to see ensure there is no current user
51
- #
52
- # @return [Boolean]
53
- # (see #current_user?)
54
- def ensure_no_user
55
- !current_user? || redirect_back_or_default
56
- end
57
-
58
- ## Utilities
59
-
60
- # Store the location URL in the session for later use.
61
- #
62
- # @return [Hash] the modified session object
63
- def store_location
64
- session[:return_to] = request.fullpath
65
- end
66
-
67
- # Stores the URL for the current requested action, then redirects to
68
- # the login page.
69
- #
70
- # @param [String] optional flash message to pass to the user
71
- # @note This method sets the redirect path, but does not return false.
72
- # Meaning you can perform actions after this method is invoked.
73
- def deny_access(message=nil)
74
- store_location
75
- flash_message :notice, message if message.present?
76
- redirect_to login_path
77
- end
78
-
79
- # Conditional redirect to handle an empty return_to path. If return_to
80
- # is empty, the request is redirected to the default path
81
- #
82
- # @param [String] path to use as the default redirect location
83
- # @return [Hash] the modified session hash
84
- def redirect_back_or_default(default=nil)
85
- default = self.default_route
86
- redirect_to(session[:return_to] || default)
87
- session[:return_to] = nil
88
- end
89
-
90
- # Fetch the User model associated with the current session.
91
- #
92
- # @return [User]
93
- # (see #current_user=)
94
10
  def current_user
95
- @current_user ||= if session[:socialite_user_id]
96
- Socialite.user_class.find(session[:socialite_user_id])
97
- elsif cookies[:remember_token]
98
- Socialite.user_class.find_by_remember_token(cookies[:remember_token])
99
- end
11
+ @current_user ||= User.find_by_id(session[:user_id])
100
12
  end
101
13
 
102
- # Assign the User model associated with the current session.
103
- #
104
- # @return [User]
105
- # (see #current_user)
106
- def current_user=(user)
107
- user.tap do |user|
108
- user.remember_me!
109
- session[:user_id] = user.id
110
- cookies[:remember_token] = user.remember_token
111
- end
112
- end
113
-
114
- # Accessor method for checking if a user is currently signed in
115
- #
116
- # @return [Boolean]
117
- # (see #current_user)
118
14
  def user_signed_in?
119
15
  !!current_user
120
16
  end
121
- alias_method :current_user?, :user_signed_in?
122
17
 
123
- # Destroy the current user session, effectively logging them out upon
124
- # the next request.
125
- #
126
- # @return [Hash] the modified session object
127
- def logout!
128
- session[:user_id] = session[:return_to] = nil
129
- @current_user = nil
130
- cookies.delete(:remember_token)
18
+ def current_user=(user)
19
+ @current_user = user
20
+ session[:user_id] = user.nil? ? user : user.id
131
21
  end
132
22
  end
133
23
  end