devise_sms_confirmable 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad0caa6d14ad6b8406d429dd6b95e6048095238dd92e2f430217748db18f8d5b
4
- data.tar.gz: 847c743ab1ff45c74d69e7759d22ea705a793a1b407499f3437ca4de4936b602
3
+ metadata.gz: a7da634ddbe05a536e69cfc4223581ca87f6f22e7aa35e6bbaaa8f8927d16cce
4
+ data.tar.gz: e779c465edf5eda673f6a90cd50b5273309c903adaebc272e3a500df3526e50d
5
5
  SHA512:
6
- metadata.gz: b28925a7656bdda3d2887051684f711b5e7397ec9bda1d8b536fb40a2b72cbba5388821b9985e7e3bcbc005ca98d71443e80f2d68a93163fbdbb6b93d0839e17
7
- data.tar.gz: 40fec62988c8c698a690edbfe46409321ff778f559c4b32023840fed3baf7ef2a0ee892ed7900e1352a7b8f6331b94cf2711f31f08f65ac08cacf1595de2725a
6
+ metadata.gz: 85925719b646dd4e7482c4d1bc9b8889a7249416504e0884fbead9dc0b4b08499791061552250e5fa326d7789da8a7d108621e521f6c7f27b6a65e071fea60fc
7
+ data.tar.gz: d87a5c77aef9b90a4e07e29629cc91ce841395538d67e30b80b7ea507ef2686f6f8636c059f688181a2125389c977232d94579b01a59dd614bcb3f5ec5395d29
data/Gemfile.lock CHANGED
@@ -1,56 +1,52 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devise_sms_confirmable (0.1.1)
4
+ devise_sms_confirmable (0.1.2)
5
5
  devise (>= 4.6.2)
6
- railties (>= 5.1.0)
6
+ rails (~> 5.1.4)
7
7
  textris (~> 0.7)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actioncable (5.2.3)
13
- actionpack (= 5.2.3)
12
+ actioncable (5.1.7)
13
+ actionpack (= 5.1.7)
14
14
  nio4r (~> 2.0)
15
- websocket-driver (>= 0.6.1)
16
- actionmailer (5.2.3)
17
- actionpack (= 5.2.3)
18
- actionview (= 5.2.3)
19
- activejob (= 5.2.3)
15
+ websocket-driver (~> 0.6.1)
16
+ actionmailer (5.1.7)
17
+ actionpack (= 5.1.7)
18
+ actionview (= 5.1.7)
19
+ activejob (= 5.1.7)
20
20
  mail (~> 2.5, >= 2.5.4)
21
21
  rails-dom-testing (~> 2.0)
22
- actionpack (5.2.3)
23
- actionview (= 5.2.3)
24
- activesupport (= 5.2.3)
22
+ actionpack (5.1.7)
23
+ actionview (= 5.1.7)
24
+ activesupport (= 5.1.7)
25
25
  rack (~> 2.0)
26
26
  rack-test (>= 0.6.3)
27
27
  rails-dom-testing (~> 2.0)
28
28
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
29
- actionview (5.2.3)
30
- activesupport (= 5.2.3)
29
+ actionview (5.1.7)
30
+ activesupport (= 5.1.7)
31
31
  builder (~> 3.1)
32
32
  erubi (~> 1.4)
33
33
  rails-dom-testing (~> 2.0)
34
34
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
35
- activejob (5.2.3)
36
- activesupport (= 5.2.3)
35
+ activejob (5.1.7)
36
+ activesupport (= 5.1.7)
37
37
  globalid (>= 0.3.6)
38
- activemodel (5.2.3)
39
- activesupport (= 5.2.3)
40
- activerecord (5.2.3)
41
- activemodel (= 5.2.3)
42
- activesupport (= 5.2.3)
43
- arel (>= 9.0)
44
- activestorage (5.2.3)
45
- actionpack (= 5.2.3)
46
- activerecord (= 5.2.3)
47
- marcel (~> 0.3.1)
48
- activesupport (5.2.3)
38
+ activemodel (5.1.7)
39
+ activesupport (= 5.1.7)
40
+ activerecord (5.1.7)
41
+ activemodel (= 5.1.7)
42
+ activesupport (= 5.1.7)
43
+ arel (~> 8.0)
44
+ activesupport (5.1.7)
49
45
  concurrent-ruby (~> 1.0, >= 1.0.2)
50
46
  i18n (>= 0.7, < 2)
51
47
  minitest (~> 5.1)
52
48
  tzinfo (~> 1.1)
53
- arel (9.0.0)
49
+ arel (8.0.0)
54
50
  bcrypt (3.1.13)
55
51
  builder (3.2.3)
56
52
  concurrent-ruby (1.1.5)
@@ -61,24 +57,27 @@ GEM
61
57
  railties (>= 4.1.0, < 6.0)
62
58
  responders
63
59
  warden (~> 1.2.3)
64
- diff-lcs (1.3)
65
60
  erubi (1.8.0)
61
+ faraday (0.15.4)
62
+ multipart-post (>= 1.2, < 3)
66
63
  globalid (0.4.2)
67
64
  activesupport (>= 4.2.0)
68
65
  i18n (1.6.0)
69
66
  concurrent-ruby (~> 1.0)
67
+ jwt (2.2.1)
70
68
  loofah (2.2.3)
71
69
  crass (~> 1.0.2)
72
70
  nokogiri (>= 1.5.9)
73
71
  mail (2.7.1)
74
72
  mini_mime (>= 0.1.1)
75
- marcel (0.3.3)
76
- mimemagic (~> 0.3.2)
73
+ metaclass (0.0.4)
77
74
  method_source (0.9.2)
78
- mimemagic (0.3.3)
79
75
  mini_mime (1.0.2)
80
76
  mini_portile2 (2.4.0)
81
77
  minitest (5.11.3)
78
+ mocha (1.9.0)
79
+ metaclass (~> 0.0.1)
80
+ multipart-post (2.1.1)
82
81
  nio4r (2.4.0)
83
82
  nokogiri (1.10.3)
84
83
  mini_portile2 (~> 2.4.0)
@@ -87,49 +86,35 @@ GEM
87
86
  rack (2.0.7)
88
87
  rack-test (1.1.0)
89
88
  rack (>= 1.0, < 3)
90
- rails (5.2.3)
91
- actioncable (= 5.2.3)
92
- actionmailer (= 5.2.3)
93
- actionpack (= 5.2.3)
94
- actionview (= 5.2.3)
95
- activejob (= 5.2.3)
96
- activemodel (= 5.2.3)
97
- activerecord (= 5.2.3)
98
- activestorage (= 5.2.3)
99
- activesupport (= 5.2.3)
89
+ rails (5.1.7)
90
+ actioncable (= 5.1.7)
91
+ actionmailer (= 5.1.7)
92
+ actionpack (= 5.1.7)
93
+ actionview (= 5.1.7)
94
+ activejob (= 5.1.7)
95
+ activemodel (= 5.1.7)
96
+ activerecord (= 5.1.7)
97
+ activesupport (= 5.1.7)
100
98
  bundler (>= 1.3.0)
101
- railties (= 5.2.3)
99
+ railties (= 5.1.7)
102
100
  sprockets-rails (>= 2.0.0)
103
101
  rails-dom-testing (2.0.3)
104
102
  activesupport (>= 4.2.0)
105
103
  nokogiri (>= 1.6)
106
104
  rails-html-sanitizer (1.0.4)
107
105
  loofah (~> 2.2, >= 2.2.2)
108
- railties (5.2.3)
109
- actionpack (= 5.2.3)
110
- activesupport (= 5.2.3)
106
+ railties (5.1.7)
107
+ actionpack (= 5.1.7)
108
+ activesupport (= 5.1.7)
111
109
  method_source
112
110
  rake (>= 0.8.7)
113
- thor (>= 0.19.0, < 2.0)
111
+ thor (>= 0.18.1, < 2.0)
114
112
  rake (12.3.0)
115
113
  render_anywhere (0.0.12)
116
114
  rails (>= 3.0.7)
117
115
  responders (3.0.0)
118
116
  actionpack (>= 5.0)
119
117
  railties (>= 5.0)
120
- rspec (3.7.0)
121
- rspec-core (~> 3.7.0)
122
- rspec-expectations (~> 3.7.0)
123
- rspec-mocks (~> 3.7.0)
124
- rspec-core (3.7.1)
125
- rspec-support (~> 3.7.0)
126
- rspec-expectations (3.7.0)
127
- diff-lcs (>= 1.2.0, < 2.0)
128
- rspec-support (~> 3.7.0)
129
- rspec-mocks (3.7.0)
130
- diff-lcs (>= 1.2.0, < 2.0)
131
- rspec-support (~> 3.7.0)
132
- rspec-support (3.7.1)
133
118
  sprockets (3.7.2)
134
119
  concurrent-ruby (~> 1.0)
135
120
  rack (> 1, < 3)
@@ -137,6 +122,7 @@ GEM
137
122
  actionpack (>= 4.0)
138
123
  activesupport (>= 4.0)
139
124
  sprockets (>= 3.0.0)
125
+ sqlite3 (1.4.1)
140
126
  textris (0.7.0)
141
127
  actionmailer (>= 4.0)
142
128
  activejob (>= 4.2)
@@ -145,11 +131,16 @@ GEM
145
131
  render_anywhere (~> 0.0)
146
132
  thor (0.20.3)
147
133
  thread_safe (0.3.6)
134
+ timecop (0.9.1)
135
+ twilio-ruby (5.25.2)
136
+ faraday (~> 0.9)
137
+ jwt (>= 1.5, <= 2.5)
138
+ nokogiri (>= 1.6, < 2.0)
148
139
  tzinfo (1.2.5)
149
140
  thread_safe (~> 0.1)
150
141
  warden (1.2.8)
151
142
  rack (>= 2.0.6)
152
- websocket-driver (0.7.1)
143
+ websocket-driver (0.6.5)
153
144
  websocket-extensions (>= 0.1.0)
154
145
  websocket-extensions (0.1.4)
155
146
 
@@ -158,9 +149,13 @@ PLATFORMS
158
149
 
159
150
  DEPENDENCIES
160
151
  bundler
152
+ devise (>= 4.6.2)
161
153
  devise_sms_confirmable!
154
+ mocha
162
155
  rake
163
- rspec
156
+ sqlite3
157
+ timecop
158
+ twilio-ruby
164
159
 
165
160
  BUNDLED WITH
166
161
  1.17.1
data/Rakefile CHANGED
@@ -1,6 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
2
+ require "rake/testtask"
3
3
 
4
- RSpec::Core::RakeTask.new(:spec)
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
5
9
 
6
- task :default => :spec
10
+ task :default => :test
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Devise::SmsConfirmationsController < DeviseController
4
+
4
5
  # GET /resource/sms_confirmation/new
5
6
  def new
6
7
  self.resource = resource_class.new
@@ -2,41 +2,51 @@
2
2
 
3
3
  if defined?(Textris)
4
4
  class Devise::Texter < Textris::Base
5
- default from: Devise.sms_sender
5
+ default from: "+48666777888"
6
6
 
7
7
  def confirmation_instructions(record, token, opts={})
8
8
  @token = token
9
9
  @resource = record
10
10
 
11
- text to: record.phone
11
+ headers = { to: @resource.phone }.merge(opts)
12
+
13
+ text to: headers[:to]
12
14
  end
13
15
 
14
16
  def reset_password_instructions(record, token, opts={})
15
17
  @token = token
16
18
  @resource = record
17
19
 
18
- text to: record.phone
20
+ headers = { to: @resource.phone }.merge(opts)
21
+
22
+ text to: headers[:to]
19
23
  end
20
24
 
21
25
  def unlock_instructions(record, token, opts={})
22
26
  @token = token
23
27
  @resource = record
24
28
 
25
- text to: record.phone
29
+ headers = { to: @resource.phone }.merge(opts)
30
+
31
+ text to: headers[:to]
26
32
  end
27
33
 
28
- def email_changed(record, token, opts={})
34
+ def phone_changed(record, token, opts={})
29
35
  @token = token
30
36
  @resource = record
31
37
 
32
- text to: record.phone
38
+ headers = { to: @resource.phone }.merge(opts)
39
+
40
+ text to: headers[:to]
33
41
  end
34
42
 
35
43
  def password_change(record, token, opts={})
36
44
  @token = token
37
45
  @resource = record
38
46
 
39
- text to: record.phone
47
+ headers = { to: @resource.phone }.merge(opts)
48
+
49
+ text to: headers[:to]
40
50
  end
41
51
  end
42
52
  end
@@ -1,5 +1,4 @@
1
1
  Welcome <%= @phone %>!
2
2
 
3
3
  You can confirm your account phone number through the link below:
4
-
5
- <%= sms_confirmation_url(@resource, confirmation_token: @token) %>
4
+ <%= session_url(@resource, confirmation_token: @token) %>
@@ -1,4 +1,3 @@
1
-
2
1
  lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "devise_sms_confirmable/version"
@@ -24,10 +23,14 @@ Gem::Specification.new do |spec|
24
23
  spec.require_paths = ["lib"]
25
24
 
26
25
  spec.add_dependency "devise", ">= 4.6.2"
27
- spec.add_dependency("railties", ">= 5.1.0")
26
+ spec.add_dependency "rails", "~> 5.1.4"
28
27
  spec.add_dependency("textris", "~> 0.7")
29
28
 
30
29
  spec.add_development_dependency "bundler"
31
30
  spec.add_development_dependency "rake"
32
- spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "sqlite3"
32
+ spec.add_development_dependency "devise", ">= 4.6.2"
33
+ spec.add_development_dependency "twilio-ruby"
34
+ spec.add_development_dependency "mocha"
35
+ spec.add_development_dependency "timecop"
33
36
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Devise
4
4
  module Models
5
- module SMSAuthenticatable
5
+ module SmsAuthenticatable
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  protected
@@ -13,7 +13,7 @@ module Devise
13
13
 
14
14
  def send_sms_devise_notification(notification, *args)
15
15
  message = devise_texter.send(notification, self, *args)
16
- message.deliver_now
16
+ message.deliver
17
17
  end
18
18
  end
19
19
  end
@@ -1,19 +1,34 @@
1
+ require_relative 'sms_authenticatable'
2
+ require_relative 'sms_validatable'
3
+
1
4
  module Devise
2
5
  module Models
3
6
  module SmsConfirmable
4
7
  extend ActiveSupport::Concern
8
+ include Devise::Models::SmsAuthenticatable
5
9
 
6
10
  included do
7
11
  before_create :generate_sms_confirmation_token, if: :sms_confirmation_required?
8
- after_create :skip_reconfirmation_in_callback!, if: :send_sms_confirmation_notification?
12
+ after_create :skip_sms_reconfirmation_in_callback!, if: :send_sms_confirmation_notification?
13
+ before_update :postpone_phone_change_until_confirmation_and_regenerate_sms_confirmation_token, if: :postpone_phone_change?
14
+ after_update :send_phone_changed_notification, if: :send_phone_changed_notification?
15
+
9
16
  after_commit :send_on_create_sms_confirmation_instructions, on: :create, if: :send_sms_confirmation_notification?
10
17
  after_commit :send_sms_reconfirmation_instructions, on: :update, if: :sms_reconfirmation_required?
11
- before_update :postpone_phone_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_phone_change?
18
+ end
19
+
20
+ def initialize(*args, &block)
21
+ @bypass_sms_confirmation_postpone = false
22
+ @skip_sms_reconfirmation_in_callback = false
23
+ @sms_reconfirmation_required = false
24
+ @skip_sms_confirmation_notification = false
25
+ @raw_sms_confirmation_token = nil
26
+ super
12
27
  end
13
28
 
14
29
  def self.required_fields(klass)
15
- required_methods = [:sms_confirmed_at, :sms_confirmation_sent_at]
16
- required_methods << :unconfirmed_phone if klass.reconfirmable
30
+ required_methods = [:sms_confirmed_at, :sms_confirmation_sent_at, :sms_confirmation_token]
31
+ required_methods << :unconfirmed_phone if klass.sms_reconfirmable
17
32
  required_methods
18
33
  end
19
34
 
@@ -21,18 +36,17 @@ module Devise
21
36
  pending_any_sms_confirmation do
22
37
  if sms_confirmation_period_expired?
23
38
  self.errors.add(:phone, :sms_confirmation_period_expired,
24
- period: Devise::TimeInflector.time_ago_in_words(self.class.confirm_within.ago))
39
+ period: Devise::TimeInflector.time_ago_in_words(self.class.sms_confirm_within.ago))
25
40
  return false
26
41
  end
27
42
 
28
43
  self.sms_confirmed_at = Time.now.utc
29
44
 
30
45
  saved = if pending_sms_reconfirmation?
31
- skip_reconfirmation!
46
+ skip_sms_reconfirmation!
32
47
  self.phone = unconfirmed_phone
33
48
  self.unconfirmed_phone = nil
34
49
 
35
- # We need to validate in such cases to enforce e-mail uniqueness
36
50
  save(validate: true)
37
51
  else
38
52
  save(validate: args[:ensure_valid] == true)
@@ -49,40 +63,77 @@ module Devise
49
63
  end
50
64
 
51
65
  def send_sms_reconfirmation_instructions
52
- @reconfirmation_required = false
66
+ @sms_reconfirmation_required = false
53
67
 
54
68
  unless @skip_confirmation_notification
55
69
  send_sms_confirmation_instructions
56
70
  end
57
71
  end
58
72
 
73
+ def skip_sms_confirmation_notification!
74
+ @skip_confirmation_notification = true
75
+ end
76
+
59
77
  def send_sms_confirmation_instructions
60
- unless @raw_confirmation_token
61
- generate_confirmation_token!
78
+ unless @raw_sms_confirmation_token
79
+ generate_sms_confirmation_token!
62
80
  end
63
81
 
64
- opts = pending_reconfirmation? ? { to: unconfirmed_phone } : { }
65
- send_sms_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
82
+ opts = pending_sms_reconfirmation? ? { to: unconfirmed_phone } : { }
83
+ send_sms_devise_notification(:confirmation_instructions, @raw_sms_confirmation_token, opts)
84
+ end
85
+
86
+ # Resend confirmation token.
87
+ # Regenerates the token if the period is expired.
88
+ def resend_sms_confirmation_instructions
89
+ pending_any_sms_confirmation do
90
+ send_sms_confirmation_instructions
91
+ end
92
+ end
93
+
94
+ def active_for_authentication?
95
+
96
+ super && (!sms_confirmation_required? || sms_confirmed? || sms_confirmation_period_valid?)
97
+ end
98
+
99
+ def send_phone_changed_notification
100
+ send_sms_devise_notification(:phone_changed, to: phone_before_last_save)
66
101
  end
67
102
 
68
- def generate_confirmation_token!
103
+ def generate_sms_confirmation_token!
69
104
  generate_sms_confirmation_token && save(validate: false)
70
105
  end
71
106
 
72
107
  # override Devise::Models::Confirmable#pending_sms_reconfirmation?
73
108
  def pending_sms_reconfirmation?
74
- self.class.reconfirmable && unconfirmed_phone.present?
109
+ self.class.sms_reconfirmable && unconfirmed_phone.present?
110
+ end
111
+
112
+ # If you don't want confirmation to be sent on create, neither a code
113
+ # to be generated, call skip_sms_confirmation!
114
+ def skip_sms_confirmation!
115
+ self.sms_confirmed_at = Time.now.utc
116
+ end
117
+
118
+ def skip_sms_reconfirmation!
119
+ @bypass_sms_confirmation_postpone = true
75
120
  end
76
121
 
77
- # protected
122
+ protected
123
+
124
+ def skip_sms_reconfirmation_in_callback!
125
+ @skip_sms_reconfirmation_in_callback = true
126
+ end
78
127
 
79
128
  def devise_texter
80
129
  Devise.texter
81
130
  end
82
131
 
83
- def send_sms_devise_notification(notification, *args)
84
- message = devise_texter.send(notification, self, *args)
85
- message.deliver_later
132
+ def sms_confirmation_period_valid?
133
+ return true if self.class.allow_sms_unconfirmed_access_for.nil?
134
+ return false if self.class.allow_sms_unconfirmed_access_for == 0.days
135
+
136
+ sms_confirmation_sent_at && sms_confirmation_sent_at.utc >= self.class.allow_sms_unconfirmed_access_for.ago
86
137
  end
87
138
 
88
139
  # A callback initiated after successfully confirming. This can be
@@ -91,7 +142,7 @@ module Devise
91
142
  #
92
143
  # Example:
93
144
  #
94
- # def after_confirmation
145
+ # def after_sms_confirmation
95
146
  # self.update_attribute(:invite_code, nil)
96
147
  # end
97
148
  #
@@ -107,16 +158,16 @@ module Devise
107
158
  end
108
159
 
109
160
  def sms_confirmation_period_expired?
110
- self.class.confirm_within && self.sms_confirmation_sent_at && (Time.now.utc > self.sms_confirmation_sent_at.utc + self.class.confirm_within)
161
+ self.class.sms_confirm_within && self.sms_confirmation_sent_at && (Time.now.utc > self.sms_confirmation_sent_at.utc + self.class.sms_confirm_within)
111
162
  end
112
163
 
113
164
  # Generates a new random token for confirmation, and stores
114
165
  # the time this token is being generated in sms_confirmation_sent_at
115
166
  def generate_sms_confirmation_token
116
- if self.confirmation_token && !confirmation_period_expired?
117
- @raw_confirmation_token = self.confirmation_token
167
+ if self.sms_confirmation_token && !sms_confirmation_period_expired?
168
+ @raw_sms_confirmation_token = self.sms_confirmation_token
118
169
  else
119
- self.confirmation_token = @raw_confirmation_token = Devise.friendly_token
170
+ self.sms_confirmation_token = @raw_sms_confirmation_token = Devise.friendly_token
120
171
  self.sms_confirmation_sent_at = Time.now.utc
121
172
  end
122
173
  end
@@ -132,12 +183,13 @@ module Devise
132
183
  end
133
184
 
134
185
  def postpone_phone_change?
135
- postpone = self.class.reconfirmable &&
186
+ postpone = self.class.sms_reconfirmable &&
136
187
  will_save_change_to_phone? &&
137
- !@bypass_confirmation_postpone &&
188
+ !@bypass_sms_confirmation_postpone &&
138
189
  self.phone.present? &&
139
- (!@skip_reconfirmation_in_callback || !self.phone_in_database.nil?)
140
- @bypass_confirmation_postpone = false
190
+ (!@skip_sms_reconfirmation_in_callback || !self.phone_in_database.nil?)
191
+ @bypass_sms_confirmation_postpone = false
192
+
141
193
  postpone
142
194
  end
143
195
 
@@ -146,51 +198,58 @@ module Devise
146
198
  end
147
199
 
148
200
  def sms_reconfirmation_required?
149
- self.class.reconfirmable && @reconfirmation_required && (self.phone.present? || self.unconfirmed_phone.present?)
201
+ self.class.sms_reconfirmable && @sms_reconfirmation_required && (self.phone.present? || self.unconfirmed_phone.present?)
150
202
  end
151
203
 
152
- def postpone_phone_change_until_confirmation_and_regenerate_confirmation_token
153
- @reconfirmation_required = true
204
+ def postpone_phone_change_until_confirmation_and_regenerate_sms_confirmation_token
205
+ @sms_reconfirmation_required = true
154
206
  self.unconfirmed_phone = self.phone
155
207
  self.phone = self.phone_in_database
156
- self.confirmation_token = nil
208
+ self.sms_confirmation_token = nil
157
209
  generate_sms_confirmation_token
158
210
  end
159
211
 
212
+ # With reconfirmable, notify the original email when the user first
213
+ # requests the email change, instead of when the change is confirmed.
214
+ def send_phone_changed_notification?
215
+ self.class.sms_reconfirmable && self.class.send_phone_changed_notification && sms_reconfirmation_required?
216
+ end
217
+
160
218
  module ClassMethods
161
219
  def send_sms_confirmation_instructions(attributes={})
162
- confirmable = find_by_unconfirmed_phone_with_errors(attributes) if reconfirmable
220
+ confirmable = find_by_unconfirmed_phone_with_errors(attributes) if sms_reconfirmable
163
221
  unless confirmable.try(:persisted?)
164
222
  confirmable = find_or_initialize_with_errors(sms_confirmation_keys, attributes, :not_found)
165
223
  end
166
- confirmable.resend_confirmation_instructions if confirmable.persisted?
224
+ confirmable.resend_sms_confirmation_instructions if confirmable.persisted?
167
225
  confirmable
168
226
  end
169
227
 
170
- def sms_confirm_by_token(confirmation_token)
171
- confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
228
+ def sms_confirm_by_token(sms_confirmation_token)
229
+ confirmable = find_first_by_auth_conditions(sms_confirmation_token: sms_confirmation_token)
172
230
  unless confirmable
173
- confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
174
- confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
231
+ confirmation_digest = Devise.token_generator.digest(self, :sms_confirmation_token, sms_confirmation_token)
232
+ confirmable = find_or_initialize_with_error_by(:sms_confirmation_token, confirmation_digest)
175
233
  end
176
234
 
177
235
  # TODO: replace above lines with
178
- # confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
236
+ # confirmable = find_or_initialize_with_error_by(:sms_confirmation_token, sms_confirmation_token)
179
237
  # after enough time has passed that Devise clients do not use digested tokens
180
238
 
181
239
  confirmable.sms_confirm if confirmable.persisted?
182
240
  confirmable
183
241
  end
184
- end
185
242
 
186
- def find_by_unconfirmed_phone_with_errors(attributes = {})
187
- attributes = attributes.slice(*sms_confirmation_keys).permit!.to_h if attributes.respond_to? :permit
188
- unconfirmed_required_attributes = sms_confirmation_keys.map { |k| k == :phone ? :unconfirmed_phone : k }
189
- unconfirmed_attributes = attributes.symbolize_keys
190
- unconfirmed_attributes[:unconfirmed_phone] = unconfirmed_attributes.delete(:phone)
191
- find_or_initialize_with_errors(unconfirmed_required_attributes, unconfirmed_attributes, :not_found)
192
- end
243
+ def find_by_unconfirmed_phone_with_errors(attributes = {})
244
+ attributes = attributes.slice(*sms_confirmation_keys).permit!.to_h if attributes.respond_to? :permit
245
+ unconfirmed_required_attributes = sms_confirmation_keys.map { |k| k == :phone ? :unconfirmed_phone : k }
246
+ unconfirmed_attributes = attributes.symbolize_keys
247
+ unconfirmed_attributes[:unconfirmed_phone] = unconfirmed_attributes.delete(:phone)
248
+ find_or_initialize_with_errors(unconfirmed_required_attributes, unconfirmed_attributes, :not_found)
249
+ end
193
250
 
251
+ Devise::Models.config(self, :allow_sms_unconfirmed_access_for, :send_phone_changed_notification, :sms_confirmation_keys, :sms_reconfirmable, :sms_confirm_within)
252
+ end
194
253
  end
195
254
  end
196
255
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Models
5
+ # Validatable creates all needed validations for a user phone and password.
6
+ # It's optional, given you may want to create the validations by yourself.
7
+ # Automatically validate if the phone is present, unique and its format is
8
+ # valid. Also tests presence of password, confirmation and length.
9
+ #
10
+ # == Options
11
+ #
12
+ # Validatable adds the following options to devise_for:
13
+ #
14
+ # * +email_regexp+: the regular expression used to validate e164 format;
15
+ #
16
+ #
17
+ module SmsValidatable
18
+ # All validations used by this module.
19
+ VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
20
+ :validates_confirmation_of, :validates_length_of].freeze
21
+
22
+ def self.required_fields(klass)
23
+ []
24
+ end
25
+
26
+ def self.included(base)
27
+ base.extend ClassMethods
28
+ assert_validations_api!(base)
29
+
30
+ base.class_eval do
31
+ validates_presence_of :phone, if: :phone_required?
32
+ validates_uniqueness_of :phone, allow_blank: true, if: :will_save_change_to_phone?
33
+ validates_format_of :phone, with: e164_phone_regexp, allow_blank: true, if: :will_save_change_to_phone?
34
+ end
35
+ end
36
+
37
+ def self.assert_validations_api!(base) #:nodoc:
38
+ unavailable_validations = VALIDATIONS.select { |v| !base.respond_to?(v) }
39
+
40
+ unless unavailable_validations.empty?
41
+ raise "Could not use :validatable module since #{base} does not respond " <<
42
+ "to the following methods: #{unavailable_validations.to_sentence}."
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ # Checks whether a password is needed or not. For validations only.
49
+ # Passwords are always required if it's a new record, or if the password
50
+ # or confirmation are being set somewhere.
51
+ def phone_required?
52
+ true
53
+ end
54
+
55
+ module ClassMethods
56
+ Devise::Models.config(self, :e164_phone_regexp)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module DeviseSmsConfirmable
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -7,11 +7,15 @@ require 'devise_sms_confirmable/engine'
7
7
 
8
8
  module Devise
9
9
  mattr_accessor :sms_confirm_within
10
- @@sms_confirm_within = 2.days
10
+ @@sms_confirm_within = nil
11
11
 
12
12
  mattr_accessor :sms_confirmation_keys
13
13
  @@sms_confirmation_keys = [:phone]
14
14
 
15
+ # Used to send notification to the original user phone when their phone is changed.
16
+ mattr_accessor :send_phone_changed_notification
17
+ @@send_phone_changed_notification = false
18
+
15
19
  mattr_accessor :parent_texter
16
20
  @@parent_texter = "Textris::Base"
17
21
 
@@ -19,6 +23,18 @@ module Devise
19
23
  mattr_accessor :sms_sender
20
24
  @@sms_sender = nil
21
25
 
26
+ mattr_accessor :e164_phone_regexp
27
+ @@e164_phone_regexp = /\A\+?[1-9]\d{1,14}\z/
28
+
29
+ # Defines if email should be sms_reconfirmable.
30
+ mattr_accessor :sms_reconfirmable
31
+ @@sms_reconfirmable = true
32
+
33
+ # Time interval you can access your account before confirming your account.
34
+ # nil - allows unconfirmed access for unlimited time
35
+ mattr_accessor :allow_sms_unconfirmed_access_for
36
+ @@allow_sms_unconfirmed_access_for = 0.days
37
+
22
38
  # Get the sms sender class from the texter reference object.
23
39
  def self.texter
24
40
  @@texter_ref.get
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise_sms_confirmable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - matsutani
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-29 00:00:00.000000000 Z
11
+ date: 2019-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.6.2
27
27
  - !ruby/object:Gem::Dependency
28
- name: railties
28
+ name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 5.1.0
33
+ version: 5.1.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 5.1.0
40
+ version: 5.1.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: textris
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,63 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rspec
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: devise
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 4.6.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 4.6.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: twilio-ruby
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: timecop
85
141
  requirement: !ruby/object:Gem::Requirement
86
142
  requirements:
87
143
  - - ">="
@@ -102,7 +158,6 @@ extensions: []
102
158
  extra_rdoc_files: []
103
159
  files:
104
160
  - ".gitignore"
105
- - ".rspec"
106
161
  - ".travis.yml"
107
162
  - CODE_OF_CONDUCT.md
108
163
  - Gemfile
@@ -113,8 +168,8 @@ files:
113
168
  - app/controllers/devise/sms_confirmations_controller.rb
114
169
  - app/texters/devise/texter.rb
115
170
  - app/views/devise/texter/confirmation_instructions.text.erb
116
- - app/views/devise/texter/email_changed.text.erb
117
171
  - app/views/devise/texter/password_change.text.erb
172
+ - app/views/devise/texter/phone_changed.text.erb
118
173
  - app/views/devise/texter/reset_password_instructions.text.erb
119
174
  - app/views/devise/texter/unlock_instructions.text.erb
120
175
  - bin/console
@@ -124,6 +179,7 @@ files:
124
179
  - lib/devise_sms_confirmable/engine.rb
125
180
  - lib/devise_sms_confirmable/models/sms_authenticatable.rb
126
181
  - lib/devise_sms_confirmable/models/sms_confirmable.rb
182
+ - lib/devise_sms_confirmable/models/sms_validatable.rb
127
183
  - lib/devise_sms_confirmable/rails/routes.rb
128
184
  - lib/devise_sms_confirmable/version.rb
129
185
  homepage: https://github.com/uuushiro/devise_sms_confirmable
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper