user_plane 0.0.15
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/user_plane/application.js +13 -0
- data/app/assets/stylesheets/user_plane/application.css +15 -0
- data/app/concerns/null_object_persistable.rb +62 -0
- data/app/controllers/user/confirm_email_addresses_controller.rb +17 -0
- data/app/controllers/user/details_controller.rb +48 -0
- data/app/controllers/user/invites_controller.rb +69 -0
- data/app/controllers/user/reset_passwords_controller.rb +50 -0
- data/app/controllers/user/sign_ins_controller.rb +53 -0
- data/app/controllers/user/sign_ups_controller.rb +47 -0
- data/app/controllers/user_plane/application_controller.rb +5 -0
- data/app/helpers/user_plane/application_helper.rb +4 -0
- data/app/mailers/user_plane/application_mailer.rb +8 -0
- data/app/mailers/user_plane/invite_mailer.rb +14 -0
- data/app/mailers/user_plane/verification_mailer.rb +25 -0
- data/app/models/session_manager.rb +100 -0
- data/app/models/user.rb +5 -0
- data/app/models/user/account.rb +26 -0
- data/app/models/user/confirm_email_address.rb +55 -0
- data/app/models/user/guest.rb +18 -0
- data/app/models/user/identities.rb +5 -0
- data/app/models/user/identities/email.rb +98 -0
- data/app/models/user/identities/email_verification.rb +70 -0
- data/app/models/user/identities/facebook.rb +5 -0
- data/app/models/user/identities/github.rb +5 -0
- data/app/models/user/identities/id_token.rb +7 -0
- data/app/models/user/identities/o_auth.rb +67 -0
- data/app/models/user/identities/o_auth_endpoint.rb +28 -0
- data/app/models/user/identities/twitter.rb +5 -0
- data/app/models/user/identity.rb +26 -0
- data/app/models/user/reset_password.rb +59 -0
- data/app/models/user/send_password_reset.rb +25 -0
- data/app/models/user/send_sign_up_invite.rb +27 -0
- data/app/models/user/sign_in.rb +42 -0
- data/app/models/user/sign_up.rb +47 -0
- data/app/models/user/sign_up_invites.rb +5 -0
- data/app/models/user/sign_up_invites/invite.rb +46 -0
- data/app/models/user/sign_up_invites/stack.rb +22 -0
- data/app/models/user/sign_up_with_invite.rb +45 -0
- data/app/models/user/suspension.rb +7 -0
- data/app/models/user/update_details.rb +103 -0
- data/app/views/layouts/user_plane/application.html.erb +14 -0
- data/app/views/user/details/edit.html.erb +37 -0
- data/app/views/user/invites/edit.html.erb +34 -0
- data/app/views/user/invites/new.html.erb +21 -0
- data/app/views/user/reset_passwords/edit.html.erb +26 -0
- data/app/views/user/reset_passwords/new.html.erb +21 -0
- data/app/views/user/sign_ins/new.html.erb +25 -0
- data/app/views/user/sign_ups/new.html.erb +33 -0
- data/app/views/user_plane/invite_mailer/invite.html.erb +2 -0
- data/app/views/user_plane/invite_mailer/invite.text.erb +3 -0
- data/app/views/user_plane/verification_mailer/address_verification.html.erb +2 -0
- data/app/views/user_plane/verification_mailer/address_verification.text.erb +4 -0
- data/app/views/user_plane/verification_mailer/password_reset.html.erb +2 -0
- data/app/views/user_plane/verification_mailer/password_reset.text.erb +4 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/locales/en.yml +63 -0
- data/config/locales/it.yml +62 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20121128143404_create_user_accounts.rb +11 -0
- data/db/migrate/20121226202553_create_user_identities_o_auths.rb +12 -0
- data/db/migrate/20121226203032_create_user_identities_emails.rb +13 -0
- data/db/migrate/20121227144617_create_user_identities_email_verifications.rb +15 -0
- data/db/migrate/20130113120152_create_user_identities_id_tokens.rb +12 -0
- data/db/migrate/20141025230304_create_user_sign_up_invites_stacks.rb +10 -0
- data/db/migrate/20141025230500_create_user_sign_up_invites_invites.rb +13 -0
- data/db/migrate/20141026230208_create_user_suspensions.rb +13 -0
- data/lib/generators/user_plane/view/details_generator.rb +22 -0
- data/lib/generators/user_plane/view/helpers.rb +68 -0
- data/lib/generators/user_plane/view/invites_generator.rb +23 -0
- data/lib/generators/user_plane/view/reset_passwords_generator.rb +22 -0
- data/lib/generators/user_plane/view/sign_ins_generator.rb +18 -0
- data/lib/generators/user_plane/view/sign_ups_generator.rb +22 -0
- data/lib/generators/user_plane/views_generator.rb +32 -0
- data/lib/tasks/user_plane_tasks.rake +4 -0
- data/lib/user_plane.rb +43 -0
- data/lib/user_plane/command.rb +24 -0
- data/lib/user_plane/engine.rb +27 -0
- data/lib/user_plane/fresh_validator.rb +9 -0
- data/lib/user_plane/omniauth.rb +50 -0
- data/lib/user_plane/redirect_to_sign_in.rb +22 -0
- data/lib/user_plane/route_concerns.rb +167 -0
- data/lib/user_plane/session_manager_concern.rb +9 -0
- data/lib/user_plane/signed_in_constraint.rb +11 -0
- data/lib/user_plane/token_segment.rb +52 -0
- data/lib/user_plane/version.rb +3 -0
- data/spec/controllers/user/confirm_email_addresses_controller_spec.rb +5 -0
- data/spec/controllers/user/details_controller_spec.rb +5 -0
- data/spec/controllers/user/invites_controller_spec.rb +19 -0
- data/spec/controllers/user/reset_passwords_controller_spec.rb +5 -0
- data/spec/controllers/user/sign_ins_controller_spec.rb +34 -0
- data/spec/controllers/user/sign_ups_controller_spec.rb +5 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +7 -0
- data/spec/dummy/app/controllers/welcome_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +30 -0
- data/spec/dummy/app/views/welcome/index.html.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +49 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/user_plane.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +43 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/schema.rb +101 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +20185 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/-pOuxJZhYk_qXqMNKgm23KfvzyUW71NynNLlcNBOubE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/3AV9ywHBH56Leqey5LeznxK9vu4HD8fF3zSTk4MiDJA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/5fzR1G0D8ukHkPkLXsUu6rP6qV82aIdx3hugKkDy6nM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/9bKtJ2lkHPqtboGfbyknZ1OyH4xYO-aml7U3qhv-3kk.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/HjDmE9SFP2wimdNHU8Nff9cm3vFZ5soO1iw7Jdlb6z8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/J9j6OdatarYW7VzVCVttmGphOhJKL0QXasdheyrgsTE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/KqrOQSlg0Th0N3XXx-h4p5BVJCfN0D8rRLoA9VxvXrc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/UCB1W65KwVU8ttOY8jnPRDp8HyyYYEjeTwwPD6R4qy8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/YmMSaaBmIcNZWPVF9jXcGBi-kwEzMuxzwPT_Zrcj1Bo.cache +2 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/g3wU8ajFWb5ZLPvujEt5l9DesbFCiAwqjx1WQgwTtHA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/i5pp88VHKoqlxQJdgmQd_lkgX1-4em_uHqNDjQ4nyHA.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/jL74yXjxf8cb6Olkjbw1C28MH_HbZe221l8AI6WVeH0.cache +3 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/puh7X4rfS3eDN9oHTXoQdAgqxivonrwAAdYZ4UB3GIg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/qxPWFIWnE6gOCY-SsdBJe7Cgm5D3YUwaEne78Y7XdRg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rM9s67WgzKMZ1bRhUdA0yhPZDlyRE5a1kmdt7cS6m4c.cache +3 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rVoG8EHlrCOgY4ZkzOj64f0jiTcbteQ_SYNzq9RqY0I.cache +0 -0
- data/spec/fabricators/user_account_fabricator.rb +11 -0
- data/spec/fabricators/user_guest_fabricator.rb +2 -0
- data/spec/fabricators/user_identities_email_fabricator.rb +8 -0
- data/spec/fabricators/user_identities_email_verification_fabricator.rb +5 -0
- data/spec/fabricators/user_identities_id_token_fabricator.rb +2 -0
- data/spec/fabricators/user_sign_up_fabricator.rb +51 -0
- data/spec/fabricators/user_sign_up_invites_invite_fabricator.rb +3 -0
- data/spec/fabricators/user_sign_up_invites_stack_fabricator.rb +4 -0
- data/spec/fabricators/user_suspension_fabricator.rb +4 -0
- data/spec/fabricators/user_update_detail_fabricator.rb +2 -0
- data/spec/features/user_plane/user_plane_invites_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_reset_passwords_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_sign_ins_spec.rb +44 -0
- data/spec/features/user_plane/user_plane_signed_in_only_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_update_details_spec.rb +43 -0
- data/spec/fixtures/user_plane/invite_mailer/invite +3 -0
- data/spec/fixtures/user_plane/verification_mailer/address_verification +3 -0
- data/spec/fixtures/user_plane/verification_mailer/password_reset +3 -0
- data/spec/lib/generators/views_generator_spec.rb +16 -0
- data/spec/lib/route_concerns_spec.rb +54 -0
- data/spec/mailers/previews/user_plane/invite_mailer_preview.rb +11 -0
- data/spec/mailers/previews/user_plane/verification_mailer_preview.rb +16 -0
- data/spec/mailers/user_plane/invite_mailer_spec.rb +25 -0
- data/spec/mailers/user_plane/verification_mailer_spec.rb +52 -0
- data/spec/models/session_manager_spec.rb +28 -0
- data/spec/models/user/account_spec.rb +26 -0
- data/spec/models/user/confirm_email_address_spec.rb +101 -0
- data/spec/models/user/guest_spec.rb +5 -0
- data/spec/models/user/identities/email_spec.rb +5 -0
- data/spec/models/user/identities/email_verification_spec.rb +42 -0
- data/spec/models/user/identities/facebook_spec.rb +5 -0
- data/spec/models/user/identities/github_spec.rb +5 -0
- data/spec/models/user/identities/id_token_spec.rb +5 -0
- data/spec/models/user/identities/o_auth_spec.rb +12 -0
- data/spec/models/user/identities/twitter_spec.rb +5 -0
- data/spec/models/user/reset_password_spec.rb +141 -0
- data/spec/models/user/send_password_reset_spec.rb +44 -0
- data/spec/models/user/send_sign_up_invite_spec.rb +30 -0
- data/spec/models/user/sign_in_spec.rb +31 -0
- data/spec/models/user/sign_up_invites/invite_spec.rb +13 -0
- data/spec/models/user/sign_up_invites/stack_spec.rb +21 -0
- data/spec/models/user/sign_up_spec.rb +58 -0
- data/spec/models/user/sign_up_with_invite_spec.rb +83 -0
- data/spec/models/user/suspension_spec.rb +5 -0
- data/spec/models/user/update_details_spec.rb +98 -0
- data/spec/routing/invites_spec.rb +49 -0
- data/spec/routing/reset_passwords_spec.rb +31 -0
- data/spec/routing/sign_ins_spec.rb +36 -0
- data/spec/routing/update_details_spec.rb +30 -0
- data/spec/shared_contexts/feature_helpers.rb +12 -0
- data/spec/shared_contexts/routing.rb +8 -0
- data/spec/shared_contexts/user.rb +67 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/fabrication.rb +7 -0
- data/spec/support/omniauth.rb +4 -0
- metadata +770 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
|
3
|
+
module UserPlane
|
4
|
+
module OmniAuth
|
5
|
+
|
6
|
+
# Lets actiondispatch figure out the request path. Looks like request_path
|
7
|
+
# needs to return the callback path to generate the correct link
|
8
|
+
def self.request_path_criteria_for provider
|
9
|
+
lambda do |env|
|
10
|
+
path_parameters = env["action_dispatch.request.path_parameters"]
|
11
|
+
path_parameters[:action] == 'oauth_request' && UserPlane::OmniAuth.custom_path(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.callback_path_criteria_for provider
|
16
|
+
lambda do |env|
|
17
|
+
path_parameters = env["action_dispatch.request.path_parameters"]
|
18
|
+
path_parameters[:action] == 'oauth_callback'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.custom_path env
|
23
|
+
path_parameters = env["action_dispatch.request.path_parameters"]
|
24
|
+
custom_callback_path = path_parameters.merge(action: 'oauth_callback',
|
25
|
+
only_path: true)
|
26
|
+
env['action_dispatch.routes'].url_for custom_callback_path
|
27
|
+
end
|
28
|
+
|
29
|
+
# Configures the omniauth middleware for the application
|
30
|
+
def self.middleware &block
|
31
|
+
controllers = [User::SignInsController,
|
32
|
+
User::SignUpsController,
|
33
|
+
User::InvitesController]
|
34
|
+
|
35
|
+
controllers.each do |controller|
|
36
|
+
controller.middleware.use Builder, &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Wraps OmniAuth::Builder to provide custom callback urls driven by the routes
|
41
|
+
class Builder < ::OmniAuth::Builder
|
42
|
+
def provider(klass, *args, &block)
|
43
|
+
options = args.extract_options!
|
44
|
+
args << options.merge(request_path: UserPlane::OmniAuth.request_path_criteria_for(klass),
|
45
|
+
callback_path: UserPlane::OmniAuth.callback_path_criteria_for(klass))
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module UserPlane
|
2
|
+
class RedirectToSignIn
|
3
|
+
def initialize route_options={}
|
4
|
+
default_route = {controller: 'user/sign_ins', action: :new}
|
5
|
+
@sign_in_route = default_route.merge(route_options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call env
|
9
|
+
session_manager = SessionManager.new(env['rack.session'])
|
10
|
+
|
11
|
+
if session_manager.signed_in?
|
12
|
+
raise ActionController::RoutingError.new('Not Found')
|
13
|
+
end
|
14
|
+
|
15
|
+
request_path = "#{env['PATH_INFO']}?#{env['QUERY_STRING']}"
|
16
|
+
session_manager.remember_page(request_path)
|
17
|
+
|
18
|
+
sign_in_path = env['action_dispatch.routes'].path_for(@sign_in_route)
|
19
|
+
[301, {'Location' => sign_in_path}, ['Redirecting to the sign in page']]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module UserPlane
|
2
|
+
module RouteConcerns
|
3
|
+
|
4
|
+
DEFAULTS = {namespace: 'user', on: :collection}
|
5
|
+
|
6
|
+
mattr_accessor :signed_in_constraint do
|
7
|
+
-> (request) {SessionManager.new(request.session).signed_in?}
|
8
|
+
end
|
9
|
+
|
10
|
+
class AbstractConcern
|
11
|
+
attr_accessor :concern_options
|
12
|
+
attr_accessor :mapper
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
defaults = RouteConcerns::DEFAULTS.merge(options)
|
16
|
+
@namespace = defaults[:namespace]
|
17
|
+
@defaults = defaults.except(:namespace)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns true if a particular concern exists
|
21
|
+
def exists? concern
|
22
|
+
mapper.instance_variable_get('@concerns').include?(concern)
|
23
|
+
end
|
24
|
+
|
25
|
+
# The abstract concern should be able to handle resources having a preferred
|
26
|
+
# collection/resource target.
|
27
|
+
def call(mapper, concern_options = {})
|
28
|
+
@mapper = mapper
|
29
|
+
@concern_options = concern_options
|
30
|
+
|
31
|
+
build
|
32
|
+
end
|
33
|
+
|
34
|
+
def options custom_route_options={}
|
35
|
+
resource_scope = mapper.send :resource_scope?
|
36
|
+
|
37
|
+
if resource_scope
|
38
|
+
@defaults.merge(@concern_options).merge(custom_route_options)
|
39
|
+
else
|
40
|
+
@defaults.merge(@concern_options).merge(custom_route_options).except(:on)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class AbstractNamespacedConcern < AbstractConcern
|
46
|
+
# The abstract concern should be able to handle resources having a preferred
|
47
|
+
# collection/resource target.
|
48
|
+
def call(mapper, concern_options = {})
|
49
|
+
@mapper = mapper
|
50
|
+
@concern_options = concern_options
|
51
|
+
|
52
|
+
mapper.namespace @namespace, path: '/' do
|
53
|
+
build
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Defines two resources:
|
59
|
+
# A session resource to sign a user in and out
|
60
|
+
# A details resource to let a user change the account's details
|
61
|
+
# It also defines an extra concern
|
62
|
+
# And a signed_in routing concern to ensure that child routes are accessible only
|
63
|
+
# to signed in users.
|
64
|
+
# It defines a route to edit the account details and one to sign in and sign out.
|
65
|
+
#
|
66
|
+
# To enforce being singed in to certain resources:
|
67
|
+
# resource :score, concern: :signed_in
|
68
|
+
#
|
69
|
+
# scope '/profile' concern: :signed_in do
|
70
|
+
# resource :score
|
71
|
+
# resource :buddies
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
class Base < AbstractNamespacedConcern
|
75
|
+
|
76
|
+
attr_accessor :singed_in_constraint
|
77
|
+
|
78
|
+
def build
|
79
|
+
mapper.resource :sign_in, options(only: [:new, :create, :destroy]) do
|
80
|
+
if exists? :auth_endpoint
|
81
|
+
mapper.concerns :auth_endpoint, controller: :sign_ins
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
mapper.resource :details, options(only: [:edit, :update],
|
86
|
+
as: :update_details,
|
87
|
+
constraints: RouteConcerns.signed_in_constraint)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class SignUp < AbstractNamespacedConcern
|
92
|
+
def build
|
93
|
+
mapper.resource :sign_up, options(only: [:new, :create]) do
|
94
|
+
if exists? :auth_endpoint
|
95
|
+
mapper.concerns :auth_endpoint, controller: :sign_ups
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# An alternative to the SignUp concern that provides routes to handle sign
|
102
|
+
# up via invites.
|
103
|
+
class Invites < AbstractNamespacedConcern
|
104
|
+
|
105
|
+
def initialize(defaults = {})
|
106
|
+
@users_can_send_invites = defaults.delete(:users_can_send_invites) || true
|
107
|
+
super
|
108
|
+
end
|
109
|
+
|
110
|
+
def build
|
111
|
+
sign_up_options = options(only: [:edit, :update],
|
112
|
+
path_names: {edit: 'redeem'},
|
113
|
+
as: :sign_up_with_invites,
|
114
|
+
param: :code)
|
115
|
+
|
116
|
+
mapper.resources :invites, sign_up_options do
|
117
|
+
if exists? :auth_endpoint
|
118
|
+
mapper.concerns :auth_endpoint, controller: :invites,
|
119
|
+
on: :member
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if @users_can_send_invites
|
124
|
+
mapper.resources :invites, options(only: [:new, :create],
|
125
|
+
as: :send_sign_up_invites,
|
126
|
+
constraints: RouteConcerns.signed_in_constraint)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Provides extra routes to manage email identities: password resets and email
|
132
|
+
# confirmations
|
133
|
+
class EmailIdentity < AbstractNamespacedConcern
|
134
|
+
def build
|
135
|
+
mapper.scope controller: :reset_passwords do
|
136
|
+
mapper.resources :reset_passwords, options(only: [:new, :create],
|
137
|
+
param: :code,
|
138
|
+
as: :send_password_resets)
|
139
|
+
|
140
|
+
mapper.resources :reset_passwords, options(only: [:edit, :update],
|
141
|
+
param: :code)
|
142
|
+
end
|
143
|
+
|
144
|
+
mapper.get '/confirm_email/:code', options(to: 'confirm_email_addresses#update',
|
145
|
+
as: :confirm_email_address)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class OAuthEndpoint < AbstractConcern
|
150
|
+
|
151
|
+
def build
|
152
|
+
controller = concern_options.delete(:controller) || 'sessions'
|
153
|
+
|
154
|
+
mapper.resources :auth, options(as: :o_auth_endpoint,
|
155
|
+
only: :edit,
|
156
|
+
path_names: {edit: 'callback'},
|
157
|
+
param: :provider,
|
158
|
+
to: "#{controller}#oauth_callback")
|
159
|
+
mapper.resources :auth, options(as: :o_auth_endpoint,
|
160
|
+
only: :show,
|
161
|
+
param: :provider,
|
162
|
+
to: "#{controller}#oauth_request")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module TokenSegment
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def has_token(attribute, options={}, &block)
|
9
|
+
# Generates a random token on a given attirubte at creation time.
|
10
|
+
# optionally it can create it for every update of the record.
|
11
|
+
|
12
|
+
validates attribute, uniqueness: true
|
13
|
+
|
14
|
+
if life_span = options[:expires_in]
|
15
|
+
scope :stale, -> {unscoped.where('created_at <= ?', life_span.ago)}
|
16
|
+
scope :fresh, -> {where('created_at > ?', life_span.ago)}
|
17
|
+
|
18
|
+
define_method :stale? do
|
19
|
+
if new_record?
|
20
|
+
false
|
21
|
+
else
|
22
|
+
created_at <= life_span.ago
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method :"regenerate_#{attribute}" do
|
28
|
+
if block_given?
|
29
|
+
make_token attribute, instance_eval(&block)
|
30
|
+
else
|
31
|
+
make_token attribute
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if regenerate_on = options[:regenerate_on]
|
36
|
+
before_validation :"regenerate_#{attribute}", on: regenerate_on
|
37
|
+
else
|
38
|
+
before_validation :"regenerate_#{attribute}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def make_token(attribute, token_string = nil)
|
47
|
+
string_to_hash = token_string || "#{self.class.name}-#{Time.now}-#{rand}-#{self.id}"
|
48
|
+
new_attributes = {attribute => Digest::SHA1.hexdigest(string_to_hash)}
|
49
|
+
self.assign_attributes new_attributes
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_contexts/user'
|
3
|
+
|
4
|
+
describe User::InvitesController, type: :controller do
|
5
|
+
include_context 'user'
|
6
|
+
render_views
|
7
|
+
|
8
|
+
# TODO: report this bug. You can't reproduce every route without use_route
|
9
|
+
# because all params are stringified, but constraints can be symbols
|
10
|
+
|
11
|
+
it 'does serve an invite page' do
|
12
|
+
session_manager = SessionManager.new(session)
|
13
|
+
session_manager.identity = a_user.email
|
14
|
+
|
15
|
+
get :new
|
16
|
+
expect(response).to have_http_status(:ok)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared_contexts/user'
|
3
|
+
|
4
|
+
describe User::SignInsController, type: :controller do
|
5
|
+
include_context 'user'
|
6
|
+
|
7
|
+
let :session_manager do
|
8
|
+
double("session_manager")
|
9
|
+
end
|
10
|
+
before {allow(subject).to receive(:session_manager).and_return(session_manager)}
|
11
|
+
|
12
|
+
describe "signing in" do
|
13
|
+
it "updates the session with the correct credentials" do
|
14
|
+
expect(session_manager).to receive(:identity=).with(a_user.email)
|
15
|
+
expect(session_manager).to receive(:remember_page).with(nil)
|
16
|
+
expect(session_manager).to receive(:previous_page)
|
17
|
+
|
18
|
+
post :create, user_sign_in: {email: a_user.email.address, password: a_user.email.password}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not log in with bad credentials" do
|
22
|
+
expect(session_manager).not_to receive(:identity=).with(a_user.email)
|
23
|
+
post :create, user_sign_in: {email: a_user.email.address, password: 'wrong password'}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "signing out" do
|
29
|
+
it "destroys the session" do
|
30
|
+
expect(session_manager).to receive(:sign_out)
|
31
|
+
get :destroy
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|