hello-rails 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -4
  3. data/app/controllers/hello/concerns/management/forgot_password.rb +1 -1
  4. data/app/controllers/hello/concerns/registration/sign_up.rb +7 -3
  5. data/app/controllers/hello/registration/sign_up_controller.rb +9 -1
  6. data/app/models/access.rb +2 -1
  7. data/app/models/credential.rb +2 -1
  8. data/app/models/email_credential.rb +2 -1
  9. data/app/models/password_credential.rb +2 -1
  10. data/app/models/user.rb +2 -1
  11. data/app/views/hello/shared/_nav_pills.html.erb +0 -2
  12. data/config/locales/hello.fr.yml +2 -4
  13. data/db/migrate/3_create_users.rb +10 -15
  14. data/lib/data/locales.yml +228 -0
  15. data/lib/generators/hello/install/install_generator.rb +8 -29
  16. data/lib/generators/hello/install/templates/initializer.rb +1 -1
  17. data/lib/generators/hello/install/templates/models/concerns/user/authorization.rb +8 -13
  18. data/lib/generators/hello/install/templates/models/user.rb +2 -1
  19. data/lib/generators/hello/users/USAGE +10 -0
  20. data/lib/generators/hello/{install/templates/users → users/templates/app}/controllers/users_controller.rb +2 -4
  21. data/lib/generators/hello/{install/templates/users → users/templates/app}/views/users/index.html.erb +1 -1
  22. data/lib/generators/hello/{install/templates/users → users/templates/app}/views/users/list.html.erb +3 -1
  23. data/lib/generators/hello/{install/templates/users → users/templates/app}/views/users/new.html.erb +2 -2
  24. data/lib/generators/hello/{install/templates/users → users/templates/app}/views/users/show.html.erb +0 -0
  25. data/lib/generators/hello/users/users_generator.rb +21 -0
  26. data/lib/hello/business/registration/sign_up.rb +30 -122
  27. data/lib/hello/locales.rb +1 -232
  28. data/lib/hello/rails_active_record/access.rb +12 -10
  29. data/lib/hello/rails_active_record/credential.rb +22 -18
  30. data/lib/hello/rails_active_record/email_credential.rb +12 -20
  31. data/lib/hello/rails_active_record/password_credential.rb +11 -32
  32. data/lib/hello/rails_active_record/user.rb +75 -54
  33. data/lib/hello/rails_controller.rb +1 -3
  34. data/lib/hello/rails_controller/restrict_by_role.rb +2 -2
  35. data/lib/hello/version.rb +1 -1
  36. data/spec/bdd/hello/authentication/classic_sign_in_spec.rb +2 -2
  37. data/spec/bdd/hello/internalionalization/anyone_can_change_their_locale/change_locale_on_the_sign_in_form_spec.rb +1 -1
  38. data/spec/bdd/hello/management/manage_email_credentials/manage_email_credentials_emails_page_spec.rb +7 -7
  39. data/spec/bdd/hello/management/manage_password_credentials/manage_password_forgot_password_spec.rb +1 -1
  40. data/spec/bdd/hello/management/manage_password_credentials/manage_password_reset_password_spec.rb +1 -1
  41. data/spec/bdd/hello/management/manage_profile/manage_profile_page_spec.rb +0 -2
  42. data/spec/bdd/hello/other/create_user_spec.rb +1 -3
  43. data/spec/bdd/hello/other/impersonate_user_spec.rb +1 -2
  44. data/spec/bdd/hello/other/list_users_spec.rb +2 -4
  45. data/spec/bdd/hello/registration/classic_sign_up_spec.rb +3 -4
  46. data/spec/bdd/hello/support.rb +0 -4
  47. data/spec/business/hello/registration/sign_up_spec.rb +10 -2
  48. data/spec/controllers/authentication_spec.rb +3 -3
  49. data/spec/models/create_and_destroy/email_credential_create_and_destroy_spec.rb +81 -0
  50. data/spec/models/create_and_destroy/password_credential_create_and_destroy_spec.rb +60 -0
  51. data/spec/models/create_and_destroy/user_create_and_destroy_spec.rb +124 -0
  52. data/spec/models/credential_spec.rb +12 -3
  53. data/spec/models/email_credential_spec.rb +1 -2
  54. data/spec/models/password_credential_spec.rb +1 -2
  55. data/spec/models/user_spec.rb +87 -27
  56. data/spec/requests/forgot_password_spec.rb +1 -1
  57. data/spec/support/factories.rb +10 -14
  58. data/spec/support/helpers/given.rb +8 -16
  59. data/spec/support/helpers/when.rb +0 -1
  60. metadata +42 -38
  61. data/lib/generators/hello/from_devise/USAGE +0 -8
  62. data/lib/generators/hello/from_devise/from_devise_generator.rb +0 -13
  63. data/lib/generators/hello/from_devise/templates/from_devise.migration.rb +0 -39
  64. data/spec/models/hello/sign_up_model_spec.rb +0 -64
@@ -1,17 +1,19 @@
1
1
  module Hello
2
2
  module RailsActiveRecord
3
- class Access < ::ActiveRecord::Base
4
- self.table_name = 'accesses'
3
+ module Access
4
+ extend ActiveSupport::Concern
5
5
 
6
- # ASSOCIATIONS
7
- belongs_to :user, counter_cache: true, class_name: '::User'
6
+ included do
7
+ # ASSOCIATIONS
8
+ belongs_to :user, counter_cache: true
8
9
 
9
- # VALIDATIONS
10
- validates_presence_of :user, :expires_at, :user_agent_string, :token
11
- validates_uniqueness_of :token
10
+ # VALIDATIONS
11
+ validates_presence_of :user, :expires_at, :user_agent_string, :token
12
+ validates_uniqueness_of :token
12
13
 
13
- before_validation on: :create do
14
- self.token = "#{user_id}-#{Hello::Encryptors::Simple.instance.single(16)}"
14
+ before_validation on: :create do
15
+ self.token = "#{user_id}-#{Hello::Encryptors::Simple.instance.single(16)}"
16
+ end
15
17
  end
16
18
 
17
19
  # CUSTOM METHODS
@@ -50,7 +52,7 @@ module Hello
50
52
  update_attributes!(expires_at: 30.minutes.from_now)
51
53
  end
52
54
 
53
- class << self
55
+ module ClassMethods
54
56
  def destroy_all_expired
55
57
  where('expires_at < ?', Time.now).destroy_all
56
58
  true
@@ -1,20 +1,27 @@
1
1
  module Hello
2
2
  module RailsActiveRecord
3
- class Credential < ::ActiveRecord::Base
4
- self.table_name = 'credentials'
3
+ module Credential
4
+ extend ActiveSupport::Concern
5
5
 
6
- # ASSOCIATIONS
7
- belongs_to :user, counter_cache: true, class_name: '::User'
6
+ included do
8
7
 
9
- # VALIDATIONS
10
- validates_presence_of :user, :type
11
- validates_inclusion_of :type, in: %w(EmailCredential PasswordCredential)
8
+ # ASSOCIATIONS
9
+ belongs_to :user, counter_cache: true
12
10
 
13
- # CUSTOM METHODS
11
+ # VALIDATIONS
12
+ validates_presence_of :user, on: :update
13
+
14
+ after_destroy do
15
+ if destroyed_by_association.nil?
16
+ if user.invalid?
17
+ user.errors.each { |k, v| errors.add(k, v) if k.to_s.include?('credentials')}
18
+ fail ActiveRecord::Rollback
19
+ end
20
+ end
21
+ end
22
+ end
14
23
 
15
- # def is_email?
16
- # is_a?(EmailCredential)
17
- # end
24
+ # CUSTOM METHODS
18
25
 
19
26
  def first_error_message
20
27
  errors.messages.values.flatten.first if errors.any?
@@ -33,19 +40,16 @@ module Hello
33
40
  uuid
34
41
  end
35
42
 
36
- def invalidate_verifying_token!
37
- update(verifying_token_digest: nil, verifying_token_digested_at: nil)
38
- end
39
-
40
- private
43
+ protected
41
44
 
42
- def hello_is_user_being_destroyed?
43
- !!Thread.current['Hello.destroying_user']
45
+ def complex_encryptor
46
+ Hello::Encryptors::Complex.instance
44
47
  end
45
48
 
46
49
  def simple_encryptor
47
50
  Hello::Encryptors::Simple.instance
48
51
  end
52
+
49
53
  end
50
54
  end
51
55
  end
@@ -1,12 +1,18 @@
1
1
  module Hello
2
2
  module RailsActiveRecord
3
- class EmailCredential < ::Credential
3
+ module EmailCredential
4
4
 
5
- # VALIDATIONS
6
- before_destroy :cannot_destroy_last_email_credential
5
+ extend ActiveSupport::Concern
7
6
 
8
- validate :hello_validations
9
- validates_uniqueness_of :email
7
+ included do
8
+ include Credential
9
+
10
+ # VALIDATIONS
11
+ validates_uniqueness_of :email
12
+ validates_presence_of :email
13
+ validate :hello_validations, if: :email?
14
+
15
+ end
10
16
 
11
17
  # SETTERS
12
18
  def email=(v)
@@ -34,27 +40,13 @@ module Hello
34
40
  private
35
41
 
36
42
  def hello_validations
37
- validates_presence_of :email
38
- return false if errors[:email].any?
43
+ return if errors.has_key?(:email)
39
44
 
40
45
  c = Hello.configuration
41
46
  validates_length_of :email, in: c.email_length
42
- return false if errors[:email].any?
43
-
44
47
  validates_format_of :email, with: c.email_regex
45
- return false if errors[:email].any?
46
- end
47
-
48
- def cannot_destroy_last_email_credential
49
- return if hello_is_user_being_destroyed?
50
- return unless is_last_email_credential?
51
- errors[:base] << 'must have at least one credential'
52
- false
53
48
  end
54
49
 
55
- def is_last_email_credential?
56
- user.email_credentials.count == 1
57
- end
58
50
  end
59
51
  end
60
52
  end
@@ -1,13 +1,16 @@
1
1
  module Hello
2
2
  module RailsActiveRecord
3
- class PasswordCredential < ::Credential
3
+ module PasswordCredential
4
+ extend ActiveSupport::Concern
4
5
 
5
- # VALIDATIONS
6
- validates_presence_of :password, on: :create
7
- # validates_presence_of :digest
6
+ included do
7
+ include Credential
8
8
 
9
- # before_destroy :cannot_destroy_last_password_credential
10
- validate :hello_validations
9
+ # VALIDATIONS
10
+ validates_presence_of :password, on: :create
11
+ validate :hello_validations, if: :digest_changed?
12
+
13
+ end
11
14
 
12
15
  # SETTERS
13
16
 
@@ -34,37 +37,13 @@ module Hello
34
37
  private
35
38
 
36
39
  def hello_validations
37
- return true unless digest_changed?
38
-
39
- return false if errors[:password].any?
40
+ return if errors.has_key?(:password)
40
41
  c = Hello.configuration
41
-
42
42
  validates_length_of :password, in: c.password_length
43
- return false if errors[:password].any?
44
-
43
+ return if errors.has_key?(:password)
45
44
  validates_format_of :password, with: c.password_regex
46
- return false if errors[:password].any?
47
45
  end
48
46
 
49
- def complex_encryptor
50
- Hello::Encryptors::Complex.instance
51
- end
52
-
53
- def simple_encryptor
54
- Hello::Encryptors::Simple.instance
55
- end
56
-
57
- # # TODO: code for multiple passwords
58
- # def cannot_destroy_last_password_credential
59
- # return if hello_is_user_being_destroyed?
60
- # return if not is_last_password_credential?
61
- # errors[:base] << "must have at least one credential"
62
- # false
63
- # end
64
-
65
- # def is_last_password_credential?
66
- # user.password_credentials.count == 1
67
- # end
68
47
  end
69
48
  end
70
49
  end
@@ -1,23 +1,26 @@
1
1
  module Hello
2
2
  module RailsActiveRecord
3
- class User < ::ActiveRecord::Base
4
- self.table_name = 'users'
3
+ module User
4
+ extend ActiveSupport::Concern
5
5
 
6
- # ASSOCIATIONS
6
+ included do
7
+ # ASSOCIATIONS
7
8
 
8
- has_many :credentials, dependent: :destroy, class_name: '::Credential'
9
- has_many :email_credentials, dependent: :destroy, class_name: '::EmailCredential'
10
- has_one :password_credential, dependent: :destroy, class_name: '::PasswordCredential'
11
- has_many :password_credentials, dependent: :destroy, class_name: '::PasswordCredential'
12
- has_many :accesses, dependent: :destroy, class_name: '::Access'
9
+ has_many :credentials, dependent: :destroy
10
+ has_many :email_credentials, dependent: :destroy
11
+ has_many :password_credentials, dependent: :destroy
12
+ has_many :accesses, dependent: :destroy
13
13
 
14
- alias :main_password_credential :password_credential
14
+ # VALIDATIONS
15
15
 
16
- # VALIDATIONS
16
+ validates_presence_of :role, :locale, :time_zone
17
+ validates_uniqueness_of :username, if: :username?
18
+ validate :hello_validations
17
19
 
18
- validates_presence_of :username, :locale, :time_zone
19
- validates_uniqueness_of :username
20
- validate :hello_validations
20
+ # DELEGATIONS
21
+
22
+ delegate :password_is?, to: :password_credential
23
+ end
21
24
 
22
25
  # SETTERS
23
26
 
@@ -25,36 +28,46 @@ module Hello
25
28
  super(v.to_s.downcase.remove(' '))
26
29
  end
27
30
 
28
- # OVERRIDES
29
-
30
- def destroy
31
- # In Rails 4.0
32
- # 'this instance' and the 'user in the credential instance'
33
- # are 2 separate instances, making it impossible for them to share state
34
- # therefore, an instance variable used as a flag will not work for Rails 4.0
35
- # It will however, work for Rails 4.1 and 4.2
36
- # @hello_is_this_being_destroyed = true
37
- Thread.current['Hello.destroying_user'] = true
38
- super
31
+ def email=(v)
32
+ return if v.blank?
33
+ if email_credentials.any?
34
+ fail "use 'email_credentials.build(email: v)' instead"
35
+ else
36
+ email_credentials.build(user: self, email: v)
37
+ end
39
38
  end
40
39
 
41
- # def hello_is_this_being_destroyed?
42
- # !!@hello_is_this_being_destroyed
43
- # end
40
+ def password=(v)
41
+ return if v.blank?
42
+ if password_credentials.any?
43
+ fail "update your 'password_credential' instead"
44
+ else
45
+ password_credential.password=v
46
+ end
47
+ end
44
48
 
49
+ # GETTERS
45
50
 
46
- # CUSTOM METHODS
51
+ def email
52
+ email_credentials.first.email
53
+ rescue
54
+ nil
55
+ end
47
56
 
48
- def as_json_web_api
49
- as_json
57
+ def password
58
+ password_credential.password # yes, it might come blank
59
+ rescue
60
+ nil
50
61
  end
51
62
 
52
- def password_is?(plain_text_password)
53
- password_credential.password_is?(plain_text_password)
63
+ def password_credential
64
+ @password_credential ||= password_credentials.first_or_initialize(user: self)
54
65
  end
55
66
 
56
- def role_is?(role)
57
- send("#{role}?")
67
+ # CUSTOM METHODS
68
+
69
+ def as_json_web_api
70
+ as_json
58
71
  end
59
72
 
60
73
  def in_any_role?(roles)
@@ -62,38 +75,46 @@ module Hello
62
75
  false
63
76
  end
64
77
 
65
- def set_generated_username
66
- loop do
67
- self.username = _make_up_new_username
68
- break if _username_unique?
69
- end
70
- end
71
-
72
78
  private
73
79
 
74
80
  def hello_validations
75
81
  c = Hello.configuration
76
-
77
82
  validates_inclusion_of :locale, in: c.locales
78
83
  validates_inclusion_of :time_zone, in: c.time_zones
79
- validates_format_of :username, with: c.username_regex
80
- validates_length_of :username, in: c.username_length
84
+
85
+ hello_validations_username(c)
86
+ hello_validations_email(c)
87
+ hello_validations_password(c)
81
88
  end
82
89
 
83
- def _make_up_new_username
84
- Hello::Encryptors::Simple.instance.single(16) # 16 chars
90
+ def hello_validations_username(c)
91
+ if c.username_presence
92
+ validates_presence_of :username
93
+ end
94
+ if username.present?
95
+ validates_format_of :username, with: c.username_regex
96
+ validates_length_of :username, in: c.username_length
97
+ end
98
+ end
99
+
100
+ def hello_validations_email(c)
101
+ if c.email_presence
102
+ validates_length_of :email_credentials, minimum: 1
103
+ validates_presence_of :email
104
+ end
85
105
  end
86
106
 
87
- def _username_unique?
88
- !self.class.unscoped.where(username: username).where.not(id: id).exists?
107
+ def hello_validations_password(c)
108
+ if new_record?
109
+ if c.password_presence
110
+ validates_presence_of :password
111
+ elsif password.blank?
112
+ password_credential.set_generated_password
113
+ end
114
+ end
115
+ validates_length_of :password_credentials, is: 1
89
116
  end
90
117
 
91
- # def username_suggestions
92
- # email1 = email.to_s.split('@').first
93
- # name1 = name.to_s.split(' ')
94
- # ideas = [name1, email1].flatten
95
- # [ideas.sample, rand(999)].join.parameterize
96
- # end
97
118
  end
98
119
  end
99
120
  end
@@ -46,7 +46,7 @@ module Hello
46
46
  end
47
47
 
48
48
  def hello_manager
49
- env['hello'] ||= Hello::RequestManager.create(request)
49
+ request.env['hello'] ||= Hello::RequestManager.create(request)
50
50
  end
51
51
 
52
52
 
@@ -106,9 +106,7 @@ module Hello
106
106
  logger.info " #{'Hello Session'.bold.light_blue} expires in #{expires_in}"
107
107
  # end keep-alive
108
108
 
109
- Thread.current['Hello.destroying_user'] = nil
110
109
  Time.use_zone(current_user.time_zone, &block)
111
- Thread.current['Hello.destroying_user'] = nil
112
110
  else
113
111
  yield
114
112
  end
@@ -21,9 +21,9 @@ module Hello
21
21
  end
22
22
 
23
23
  def to_home_page
24
- if current_user.guest?
24
+ if current_user.role_is? 'guest'
25
25
  to_sign_in
26
- elsif current_user.onboarding?
26
+ elsif current_user.role_is? 'onboarding'
27
27
  to_onboarding
28
28
  else
29
29
  to_root
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Hello
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.5.1'.freeze
4
4
  end
@@ -5,7 +5,7 @@ RSpec.bdd.capability 'I can Sign In With Email' do
5
5
  role 'User' do
6
6
 
7
7
  before do
8
- given_I_have_an_email_credential
8
+ given_I_have_a_user
9
9
  expect(Access.count).to eq(0)
10
10
  end
11
11
 
@@ -222,7 +222,7 @@ RSpec.bdd.capability 'I can Sign In With Email' do
222
222
 
223
223
  Then 'I should see the access object' do
224
224
  expect(json_response.keys).to match_array ['expires_at', 'token', 'user', 'user_id']
225
- expect(json_response['user'].keys).to match_array ['id', 'accesses_count', 'city', 'created_at', 'credentials_count', 'locale', 'name', 'role', 'time_zone', 'updated_at', 'username']
225
+ expect(json_response['user'].keys).to match_array ['id', 'accesses_count', 'created_at', 'credentials_count', 'locale', 'name', 'role', 'time_zone', 'updated_at', 'username']
226
226
  end
227
227
 
228
228
  Then 'I should get a 201 response' do
@@ -13,7 +13,7 @@ RSpec.bdd.uic "On The Sign In Form" do
13
13
  end
14
14
 
15
15
  When "I sign in to a 'pt-BR' user" do
16
- user = given_I_have_an_email_credential.user
16
+ user = given_I_have_a_user
17
17
  user.update! locale: 'pt-BR'
18
18
  when_sign_in_with_standard_data(skip_expire: true)
19
19
  end