hello-rails 0.5.0 → 0.5.1

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