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,67 @@
|
|
1
|
+
module User
|
2
|
+
module Identities
|
3
|
+
|
4
|
+
# The class methods have been moved into a separate module so that they
|
5
|
+
# could be added as association extensions if necessary.
|
6
|
+
module OauthBuildCreateAndFind
|
7
|
+
|
8
|
+
def find_identity sign_in
|
9
|
+
find_from_omniauth(sign_in[:oauth_data])
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_identity sign_up
|
13
|
+
identity = initialize_from_omniauth(sign_up[:oauth_data])
|
14
|
+
sign_up.account.oauth_identities << identity
|
15
|
+
|
16
|
+
identity
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize_from_omniauth ominauth_data
|
20
|
+
identity_provider = provider_from_ominauth(ominauth_data)
|
21
|
+
identity_provider.new(ominauth_data: ominauth_data)
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_from_omniauth ominauth_data
|
25
|
+
identity_provider = provider_from_ominauth(ominauth_data)
|
26
|
+
identity_provider.find_by(uid: ominauth_data[:uid])
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_or_build_from_omniauth ominauth_data
|
30
|
+
find_from_omniauth(ominauth_data) || initialize_from_omniauth(ominauth_data)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def provider_from_ominauth ominauth_data
|
35
|
+
User::Identities.const_get(ominauth_data[:provider].camelize)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class OAuth < Identity
|
40
|
+
# Base class for omniauth-based user authentication
|
41
|
+
|
42
|
+
self.inheritance_column = :provider
|
43
|
+
include SupportSegment::StiHelpers
|
44
|
+
extend OauthBuildCreateAndFind
|
45
|
+
|
46
|
+
belongs_to :account, class_name: 'User::Account'
|
47
|
+
has_one :id_token, as: :identity
|
48
|
+
|
49
|
+
validates :uid, presence: true,
|
50
|
+
uniqueness: {scope: :provider}
|
51
|
+
|
52
|
+
def self.callback
|
53
|
+
OAuthCallback.new(self.name.underscore.to_sym)
|
54
|
+
end
|
55
|
+
|
56
|
+
before_validation do
|
57
|
+
self.build_id_token
|
58
|
+
end
|
59
|
+
|
60
|
+
def ominauth_data= new_ominauth_data
|
61
|
+
self.uid = new_ominauth_data[:uid]
|
62
|
+
self.handle = new_ominauth_data[:info][:name]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module User::Identities
|
2
|
+
class OAuthEndpoint
|
3
|
+
extend ActiveModel::Naming
|
4
|
+
|
5
|
+
attr_accessor :provider
|
6
|
+
|
7
|
+
def initialize provider
|
8
|
+
@provider = provider
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_param
|
12
|
+
provider
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_model
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def persisted?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.model_name
|
24
|
+
ActiveModel::Name.new(self, nil, "OAuthEndpoint")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module User
|
2
|
+
class Identity < ActiveRecord::Base
|
3
|
+
self.abstract_class = true
|
4
|
+
|
5
|
+
def serialize
|
6
|
+
# TODO: create the token when it's missing
|
7
|
+
id_token.key
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.deserialize id_token
|
11
|
+
token = Identities::IdToken.find_by_key(id_token)
|
12
|
+
token ? token.identity : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.deserialize! id_token
|
16
|
+
identity = deserialize(id_token)
|
17
|
+
if identity
|
18
|
+
raise User::AccountSuspended unless identity.account.suspensions.empty?
|
19
|
+
identity
|
20
|
+
else
|
21
|
+
raise ActiveRecord::RecordNotFound
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module User
|
2
|
+
class ResetPassword < UserPlane::Command
|
3
|
+
include ActiveModel::Validations::Callbacks
|
4
|
+
|
5
|
+
attribute :password
|
6
|
+
attribute :password_confirmation
|
7
|
+
|
8
|
+
attr_accessor :code
|
9
|
+
attr_accessor :verification
|
10
|
+
attr_accessor :identity
|
11
|
+
|
12
|
+
validates :password, :password_confirmation, presence: true
|
13
|
+
validate {|r| r.errors.add(:code, 'is not valid') unless r.verification}
|
14
|
+
validates :verification, presence: true,
|
15
|
+
receiver: {map_attributes: {created_at: :code,
|
16
|
+
base: :code,
|
17
|
+
spent_at: :code}}
|
18
|
+
validates :identity, receiver: {map_attributes: {password: :password,
|
19
|
+
password_confirmation: :password_confirmation}}
|
20
|
+
|
21
|
+
def to_param
|
22
|
+
self.code
|
23
|
+
end
|
24
|
+
|
25
|
+
def persisted?
|
26
|
+
verification && verification.persisted?
|
27
|
+
end
|
28
|
+
|
29
|
+
def code= token
|
30
|
+
@code = token
|
31
|
+
|
32
|
+
password_reset_query = User::Identities::EmailVerification.password_reset.where(token: code)
|
33
|
+
if @identity = User::Identities::Email.joins(:verifications).merge(password_reset_query).first
|
34
|
+
@verification = identity.verifications.detect {|v| v.token == code}
|
35
|
+
else
|
36
|
+
raise ActiveRecord::RecordNotFound
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def verification= verification
|
41
|
+
return unless verification
|
42
|
+
@code = verification.token
|
43
|
+
@verification = verification
|
44
|
+
@identity = verification.email
|
45
|
+
end
|
46
|
+
|
47
|
+
before_validation do
|
48
|
+
if verification
|
49
|
+
identity.attributes = {password: password,
|
50
|
+
password_confirmation: password_confirmation}
|
51
|
+
verification.spend
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
action do
|
56
|
+
identity.save
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module User
|
2
|
+
class SendPasswordReset < UserPlane::Command
|
3
|
+
attribute :email
|
4
|
+
attr_accessor :code
|
5
|
+
attr_accessor :identity
|
6
|
+
attr_accessor :verification
|
7
|
+
|
8
|
+
def email= address
|
9
|
+
@identity = User::Identities::Email.find_by_address(address)
|
10
|
+
@email = address
|
11
|
+
end
|
12
|
+
|
13
|
+
def persisited?
|
14
|
+
verification ? verification.persisted? : false
|
15
|
+
end
|
16
|
+
|
17
|
+
action do
|
18
|
+
if identity
|
19
|
+
@verification ||= identity.reset_password!
|
20
|
+
@code ||= verification.token
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module User
|
2
|
+
class SendSignUpInvite < UserPlane::Command
|
3
|
+
include ActiveModel::Validations::Callbacks
|
4
|
+
|
5
|
+
attribute :recipient
|
6
|
+
attribute :invite
|
7
|
+
attribute :stack
|
8
|
+
attribute :sender
|
9
|
+
|
10
|
+
validates :invite, receiver: {map_attributes: {recipient: :recipient}}
|
11
|
+
validates :stack, receiver: {map_attributes: {remaining_invites: :remaining_invites}}
|
12
|
+
|
13
|
+
before_validation do
|
14
|
+
# The stack can be provided directly if other models have a stack of invites
|
15
|
+
@stack ||= sender.invites_stack
|
16
|
+
@invite ||= stack.invites.build(recipient: recipient, sender: sender)
|
17
|
+
end
|
18
|
+
|
19
|
+
def persisited?
|
20
|
+
invite ? invite.persisted? : false
|
21
|
+
end
|
22
|
+
|
23
|
+
action do
|
24
|
+
invite.save
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module User
|
2
|
+
class SignIn < UserPlane::Command
|
3
|
+
include ActiveModel::Validations::Callbacks
|
4
|
+
|
5
|
+
model_name.instance_variable_set(:@route_key, 'user_sign_in')
|
6
|
+
|
7
|
+
attribute :email
|
8
|
+
attribute :password
|
9
|
+
attribute :oauth_data
|
10
|
+
attribute :strategy
|
11
|
+
attr_accessor :ominauth_error
|
12
|
+
|
13
|
+
attribute :identity
|
14
|
+
|
15
|
+
validates :ominauth_error, absence: true
|
16
|
+
|
17
|
+
|
18
|
+
validate do |command|
|
19
|
+
if identity = command.identity
|
20
|
+
unless identity.account.suspensions.empty?
|
21
|
+
command.errors.add(:base, :suspended)
|
22
|
+
end
|
23
|
+
elsif strategy = command.strategy
|
24
|
+
sign_in_error = :"unknown_#{strategy.model_name.singular}"
|
25
|
+
command.errors.add(:base, sign_in_error)
|
26
|
+
else
|
27
|
+
raise "Please choose a strategy to perform the sign in"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def sign_in_with strategy
|
32
|
+
@strategy = strategy
|
33
|
+
@identity = strategy.find_identity(self) if identity.nil?
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
action do
|
38
|
+
@identity
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module User
|
2
|
+
class SignUp < UserPlane::Command
|
3
|
+
include ActiveModel::Validations::Callbacks
|
4
|
+
|
5
|
+
attribute :user_name
|
6
|
+
|
7
|
+
attribute :email
|
8
|
+
attribute :password
|
9
|
+
attribute :password_confirmation
|
10
|
+
|
11
|
+
attribute :account
|
12
|
+
attribute :identity
|
13
|
+
|
14
|
+
attribute :oauth_data
|
15
|
+
|
16
|
+
# Validate command receivers
|
17
|
+
validates :identity, receiver: {map_attributes: {address: :email,
|
18
|
+
password: :password,
|
19
|
+
password_confirmation: :password_confirmation,
|
20
|
+
uid: :account}}
|
21
|
+
validates :account, receiver: {map_attributes: {name: :user_name,
|
22
|
+
identities: :email_or_omniauth}}
|
23
|
+
|
24
|
+
def sign_up_with sign_up_strategy
|
25
|
+
@identity = sign_up_strategy.build_identity(self) if identity.nil?
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def account
|
30
|
+
@account ||= new_account
|
31
|
+
end
|
32
|
+
|
33
|
+
action do
|
34
|
+
ActiveRecord::Base.transaction do
|
35
|
+
raise ActiveRecord::Rollback unless account.save
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def new_account
|
42
|
+
Account.new(name: user_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module User::SignUpInvites
|
2
|
+
class Invite < ActiveRecord::Base
|
3
|
+
include TokenSegment
|
4
|
+
|
5
|
+
|
6
|
+
belongs_to :stack
|
7
|
+
belongs_to :sender, class_name: 'User::Account'
|
8
|
+
belongs_to :account, class_name: 'User::Account'
|
9
|
+
has_token :code
|
10
|
+
|
11
|
+
validates :recipient, email: true
|
12
|
+
|
13
|
+
# Once an invite has been associated with an account it cannot be reused
|
14
|
+
validate on: :update do |r|
|
15
|
+
if account_id_changed?
|
16
|
+
previous, current = account_id_change
|
17
|
+
r.errors.add(:base, :redeemed) unless previous.nil?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a Null invite
|
22
|
+
def self.find_by_code code
|
23
|
+
find_by(code: code) || Null.new(code)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
# A Null invite is an invite-like object created when the invite code is not
|
29
|
+
# valid. It will
|
30
|
+
Null = Struct.new(:code) do
|
31
|
+
include ActiveModel::Validations
|
32
|
+
include NullObjectPersistable
|
33
|
+
|
34
|
+
mimics_persistence_from Invite
|
35
|
+
validate {|r| r.errors.add(:base, :invalid) }
|
36
|
+
|
37
|
+
def method_missing method_name, *arguments
|
38
|
+
return nil if [:stack, :sender, :recipient].include? method_name
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def persisted?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class User::SignUpInvites::Stack < ActiveRecord::Base
|
2
|
+
belongs_to :owner, polymorphic: true
|
3
|
+
has_many :invites, before_add: :decrement_remaining_invites
|
4
|
+
after_initialize :set_remaining_invites
|
5
|
+
|
6
|
+
# FIXME: the validation above should be enough, but doesn't seem to take effect
|
7
|
+
# validates :remaining_invites, numericality: {greater_than_or_equal: 0}
|
8
|
+
validate do |record|
|
9
|
+
record.errors.add(:remaining_invites, :greater_than_or_equal, value: 0) unless (record.remaining_invites >= 0)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def decrement_remaining_invites invite
|
15
|
+
self.remaining_invites -= 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_remaining_invites
|
19
|
+
self.remaining_invites ||= 0
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# set_callback :invite_set, :after, :set_email_from_invite
|
2
|
+
module User
|
3
|
+
class SignUpWithInvite < SignUp
|
4
|
+
attribute :invite
|
5
|
+
attr_accessor :code
|
6
|
+
|
7
|
+
|
8
|
+
define_callbacks :invite_set
|
9
|
+
|
10
|
+
validates :invite, receiver: {map_attributes: {created_at: :invite,
|
11
|
+
base: :invite,
|
12
|
+
spent: :invite}}
|
13
|
+
|
14
|
+
validate do |command|
|
15
|
+
# Enforces the need of an invite if the account does not exist
|
16
|
+
if command.account.new_record?
|
17
|
+
command.errors.add_on_blank(:invite) if command.invite.nil?
|
18
|
+
else
|
19
|
+
command.errors.add(:base, :exists)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_param
|
24
|
+
self.code
|
25
|
+
end
|
26
|
+
|
27
|
+
def persisted?
|
28
|
+
invite && invite.persisted?
|
29
|
+
end
|
30
|
+
|
31
|
+
def code= code
|
32
|
+
self.invite = SignUpInvites::Invite.find_by_code(code)
|
33
|
+
end
|
34
|
+
|
35
|
+
def invite= invite
|
36
|
+
@code = invite.code
|
37
|
+
run_callbacks(:invite_set) {@invite = invite}
|
38
|
+
end
|
39
|
+
|
40
|
+
before_validation do
|
41
|
+
account.invite = invite
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|