devise-approvable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +80 -0
- data/README +5 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/config/initializers/devise.rb +110 -0
- data/device-approvable.gemspec +62 -0
- data/lib/approvable.rb +174 -0
- data/lib/approvable_mailer.rb +11 -0
- data/test/approvable_test.rb +245 -0
- data/views/devise_mailer/approval_instructions.html.erb +11 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 43563bae7032e34e41cab9ee979c4feaaa970f9c
|
4
|
+
data.tar.gz: c7b1715ae51fcc386e48e87d37f69d1b953fe636
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d8a66a0e1fb792ab6219a27067868e8b2539aa64f604102eb9808776102ee3d137852e92a4c26589842875ec6ce585bab21d499ea2089be7137be096f978a54c
|
7
|
+
data.tar.gz: 4e08ed659937ef98930e29c10ac2fc5382153a46810eabc6889f710417a88ace622fe810f729b94ae096d286ac5753b29b49dac6c9f953da54c46bec9e2526f8
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "rdoc", "~> 3.12"
|
11
|
+
gem "bundler", "~> 1.0"
|
12
|
+
gem "jeweler", "~> 2.0.1"
|
13
|
+
gem "simplecov", ">= 0"
|
14
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (4.2.1)
|
5
|
+
i18n (~> 0.7)
|
6
|
+
json (~> 1.7, >= 1.7.7)
|
7
|
+
minitest (~> 5.1)
|
8
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
9
|
+
tzinfo (~> 1.1)
|
10
|
+
addressable (2.3.8)
|
11
|
+
builder (3.2.2)
|
12
|
+
descendants_tracker (0.0.4)
|
13
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
14
|
+
docile (1.1.5)
|
15
|
+
faraday (0.9.1)
|
16
|
+
multipart-post (>= 1.2, < 3)
|
17
|
+
git (1.2.9.1)
|
18
|
+
github_api (0.12.3)
|
19
|
+
addressable (~> 2.3)
|
20
|
+
descendants_tracker (~> 0.0.4)
|
21
|
+
faraday (~> 0.8, < 0.10)
|
22
|
+
hashie (>= 3.3)
|
23
|
+
multi_json (>= 1.7.5, < 2.0)
|
24
|
+
nokogiri (~> 1.6.3)
|
25
|
+
oauth2
|
26
|
+
hashie (3.4.1)
|
27
|
+
highline (1.7.1)
|
28
|
+
i18n (0.7.0)
|
29
|
+
jeweler (2.0.1)
|
30
|
+
builder
|
31
|
+
bundler (>= 1.0)
|
32
|
+
git (>= 1.2.5)
|
33
|
+
github_api
|
34
|
+
highline (>= 1.6.15)
|
35
|
+
nokogiri (>= 1.5.10)
|
36
|
+
rake
|
37
|
+
rdoc
|
38
|
+
json (1.8.2)
|
39
|
+
jwt (1.4.1)
|
40
|
+
mini_portile (0.6.2)
|
41
|
+
minitest (5.5.1)
|
42
|
+
multi_json (1.11.0)
|
43
|
+
multi_xml (0.5.5)
|
44
|
+
multipart-post (2.0.0)
|
45
|
+
nokogiri (1.6.6.2)
|
46
|
+
mini_portile (~> 0.6.0)
|
47
|
+
oauth2 (1.0.0)
|
48
|
+
faraday (>= 0.8, < 0.10)
|
49
|
+
jwt (~> 1.0)
|
50
|
+
multi_json (~> 1.3)
|
51
|
+
multi_xml (~> 0.5)
|
52
|
+
rack (~> 1.2)
|
53
|
+
rack (1.6.0)
|
54
|
+
rake (10.4.2)
|
55
|
+
rdoc (3.12.2)
|
56
|
+
json (~> 1.4)
|
57
|
+
shoulda (3.5.0)
|
58
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
59
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
60
|
+
shoulda-context (1.2.1)
|
61
|
+
shoulda-matchers (2.8.0)
|
62
|
+
activesupport (>= 3.0.0)
|
63
|
+
simplecov (0.9.2)
|
64
|
+
docile (~> 1.1.0)
|
65
|
+
multi_json (~> 1.0)
|
66
|
+
simplecov-html (~> 0.9.0)
|
67
|
+
simplecov-html (0.9.0)
|
68
|
+
thread_safe (0.3.5)
|
69
|
+
tzinfo (1.2.2)
|
70
|
+
thread_safe (~> 0.1)
|
71
|
+
|
72
|
+
PLATFORMS
|
73
|
+
ruby
|
74
|
+
|
75
|
+
DEPENDENCIES
|
76
|
+
bundler (~> 1.0)
|
77
|
+
jeweler (~> 2.0.1)
|
78
|
+
rdoc (~> 3.12)
|
79
|
+
shoulda
|
80
|
+
simplecov
|
data/README
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
An approvable module. This includes all confirmable functions as approval should happen before confirmation.
|
2
|
+
|
3
|
+
Workflow:
|
4
|
+
|
5
|
+
Admin email should be added to the configuration. When user signs up admin receives email with link to approve user. Admin clicks link with token. User is approved. Confirmation email gets sent to user. User clicks confirmation link. Profit.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "devise-approvable"
|
18
|
+
gem.homepage = "http://github.com/eggie5/devise-approvable"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Oh so perfect}
|
21
|
+
gem.description = %Q{adds feature to devise}
|
22
|
+
gem.email = "eggie5@gmail.com"
|
23
|
+
gem.authors = ["Alex Egg"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Code coverage detail"
|
36
|
+
task :simplecov do
|
37
|
+
ENV['COVERAGE'] = "true"
|
38
|
+
Rake::Task['test'].execute
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rdoc/task'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "devise-approvable #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'devise/approvable_mailer'
|
2
|
+
# Use this hook to configure devise mailer, warden hooks and so forth. The first
|
3
|
+
# four configuration values can also be set straight in your models.
|
4
|
+
Devise.setup do |config|
|
5
|
+
# Configure the e-mail address which will be shown in DeviseMailer.
|
6
|
+
config.mailer_sender = "support@yoursite.ca" # .CA because clearly you're Canadian
|
7
|
+
config.approval_recepient = "admin@yourcandaiansite.ca"
|
8
|
+
|
9
|
+
# Configure the content type of DeviseMailer mails (defaults to text/html")
|
10
|
+
# config.mailer_content_type = "text/plain"
|
11
|
+
|
12
|
+
# ==> Configuration for :authenticatable
|
13
|
+
# Invoke `rake secret` and use the printed value to setup a pepper to generate
|
14
|
+
# the encrypted password. By default no pepper is used.
|
15
|
+
# config.pepper = "rake secret output"
|
16
|
+
|
17
|
+
# Configure how many times you want the password is reencrypted. Default is 10.
|
18
|
+
# config.stretches = 10
|
19
|
+
|
20
|
+
# Define which will be the encryption algorithm. Supported algorithms are :sha1
|
21
|
+
# (default), :sha512 and :bcrypt. Devise also supports encryptors from others
|
22
|
+
# authentication tools as :clearance_sha1, :authlogic_sha512 (then you should set
|
23
|
+
# stretches above to 20 for default behavior) and :restful_authentication_sha1
|
24
|
+
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
|
25
|
+
# config.encryptor = :sha1
|
26
|
+
|
27
|
+
# Configure which keys are used when authenticating an user. By default is
|
28
|
+
# just :email. You can configure it to use [:username, :subdomain], so for
|
29
|
+
# authenticating an user, both parameters are required. Remember that those
|
30
|
+
# parameters are used only when authenticating and not when retrieving from
|
31
|
+
# session. If you need permissions, you should implement that in a before filter.
|
32
|
+
# config.authentication_keys = [ :email ]
|
33
|
+
|
34
|
+
# The realm used in Http Basic Authentication
|
35
|
+
# config.http_authentication_realm = "Application"
|
36
|
+
|
37
|
+
# ==> Configuration for :confirmable
|
38
|
+
# The time you want give to your user to confirm his account. During this time
|
39
|
+
# he will be able to access your application without confirming. Default is nil.
|
40
|
+
# config.confirm_within = 2.days
|
41
|
+
|
42
|
+
# ==> Configuration for :rememberable
|
43
|
+
# The time the user will be remembered without asking for credentials again.
|
44
|
+
# config.remember_for = 2.weeks
|
45
|
+
|
46
|
+
# ==> Configuration for :timeoutable
|
47
|
+
# The time you want to timeout the user session without activity. After this
|
48
|
+
# time the user will be asked for credentials again.
|
49
|
+
# config.timeout_in = 10.minutes
|
50
|
+
|
51
|
+
# ==> Configuration for :lockable
|
52
|
+
# Number of authentication tries before locking an account.
|
53
|
+
# config.maximum_attempts = 20
|
54
|
+
|
55
|
+
# Defines which strategy will be used to unlock an account.
|
56
|
+
# :email = Sends an unlock link to the user email
|
57
|
+
# :time = Reanables login after a certain ammount of time (see :unlock_in below)
|
58
|
+
# :both = enables both strategies
|
59
|
+
# config.unlock_strategy = :both
|
60
|
+
|
61
|
+
# Time interval to unlock the account if :time is enabled as unlock_strategy.
|
62
|
+
# config.unlock_in = 1.hour
|
63
|
+
|
64
|
+
# ==> Configuration for :token_authenticatable
|
65
|
+
# Defines name of the authentication token params key
|
66
|
+
# config.token_authentication_key = :auth_token
|
67
|
+
|
68
|
+
# ==> General configuration
|
69
|
+
# Load and configure the ORM. Supports :active_record (default), :mongo_mapper
|
70
|
+
# (requires mongo_ext installed) and :data_mapper (experimental).
|
71
|
+
# require 'devise/orm/mongo_mapper'
|
72
|
+
# config.orm = :mongo_mapper
|
73
|
+
|
74
|
+
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
75
|
+
# "sessions/users/new". It's turned off by default because it's slower if you
|
76
|
+
# are using only default views.
|
77
|
+
# config.scoped_views = true
|
78
|
+
|
79
|
+
# By default, devise detects the role accessed based on the url. So whenever
|
80
|
+
# accessing "/users/sign_in", it knows you are accessing an User. This makes
|
81
|
+
# routes as "/sign_in" not possible, unless you tell Devise to use the default
|
82
|
+
# scope, setting true below.
|
83
|
+
config.use_default_scope = true
|
84
|
+
|
85
|
+
# Configure the default scope used by Devise. By default it's the first devise
|
86
|
+
# role declared in your routes.
|
87
|
+
config.default_scope = :user
|
88
|
+
|
89
|
+
# If you want to use other strategies, that are not (yet) supported by Devise,
|
90
|
+
# you can configure them inside the config.warden block. The example below
|
91
|
+
# allows you to setup OAuth, using http://github.com/roman/warden_oauth
|
92
|
+
#
|
93
|
+
# config.warden do |manager|
|
94
|
+
# manager.oauth(:twitter) do |twitter|
|
95
|
+
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
|
96
|
+
# twitter.consumer_key = <YOUR CONSUMER KEY>
|
97
|
+
# twitter.options :site => 'http://twitter.com'
|
98
|
+
# end
|
99
|
+
# manager.default_strategies.unshift :twitter_oauth
|
100
|
+
# end
|
101
|
+
|
102
|
+
# Configure default_url_options if you are using dynamic segments in :path_prefix
|
103
|
+
# for devise_for.
|
104
|
+
# config.default_url_options do
|
105
|
+
# { :locale => I18n.locale }
|
106
|
+
# end
|
107
|
+
|
108
|
+
config.add_module(:approvable, :model => 'devise/approvable')
|
109
|
+
config.add_module(:approvable_email, :model => 'devise/approvable_mailer')
|
110
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: devise-approvable 0.1.0 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "devise-approvable"
|
9
|
+
s.version = "0.1.0"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Alex Egg"]
|
14
|
+
s.date = "2015-04-03"
|
15
|
+
s.description = "adds feature to devise"
|
16
|
+
s.email = "eggie5@gmail.com"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"README",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"config/initializers/devise.rb",
|
27
|
+
"devise-approvable.gemspec",
|
28
|
+
"lib/approvable.rb",
|
29
|
+
"lib/approvable_mailer.rb",
|
30
|
+
"test/approvable_test.rb",
|
31
|
+
"views/devise_mailer/approval_instructions.html.erb"
|
32
|
+
]
|
33
|
+
s.homepage = "http://github.com/eggie5/devise-approvable"
|
34
|
+
s.licenses = ["MIT"]
|
35
|
+
s.rubygems_version = "2.2.1"
|
36
|
+
s.summary = "Oh so perfect"
|
37
|
+
|
38
|
+
if s.respond_to? :specification_version then
|
39
|
+
s.specification_version = 4
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
43
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
44
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
45
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
46
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
49
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
50
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
51
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
52
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
57
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
58
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
59
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/lib/approvable.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
module Approvable
|
4
|
+
# extend ActiveSupport::Concern #RAILS 3
|
5
|
+
include Devise::Models::Activatable
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
extend ClassMethods
|
10
|
+
|
11
|
+
before_create :generate_approval_token, :if => :approval_required?
|
12
|
+
# after_create :send_approval_instructions unless approved?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
17
|
+
# is already confirmed, add en error to email field
|
18
|
+
def confirm!
|
19
|
+
unless_confirmed do
|
20
|
+
self.confirmation_token = nil
|
21
|
+
self.confirmed_at = Time.now
|
22
|
+
save(false)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Verifies whether a user is confirmed or not
|
27
|
+
def confirmed?
|
28
|
+
!new_record? && !confirmed_at.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Send confirmation instructions by email
|
32
|
+
def send_confirmation_instructions
|
33
|
+
generate_confirmation_token if self.confirmation_token.nil?
|
34
|
+
::DeviseMailer.deliver_confirmation_instructions(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Resend confirmation token. This method does not need to generate a new token.
|
38
|
+
def resend_confirmation_token
|
39
|
+
unless_confirmed { send_confirmation_instructions }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Overwrites active? from Devise::Models::Activatable for confirmation
|
43
|
+
# by verifying whether an user is active to sign in or not. If the user
|
44
|
+
# is already confirmed, it should never be blocked. Otherwise we need to
|
45
|
+
# calculate if the confirm time has not expired for this user.
|
46
|
+
def active?
|
47
|
+
super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
|
48
|
+
end
|
49
|
+
|
50
|
+
# The message to be shown if the account is inactive.
|
51
|
+
def inactive_message
|
52
|
+
!confirmed? ? :unconfirmed : super
|
53
|
+
end
|
54
|
+
|
55
|
+
# If you don't want confirmation to be sent on create, neither a code
|
56
|
+
# to be generated, call skip_confirmation!
|
57
|
+
def skip_confirmation!
|
58
|
+
self.confirmed_at = Time.now
|
59
|
+
@skip_confirmation = true
|
60
|
+
end
|
61
|
+
|
62
|
+
def skip_confirm_and_approve!
|
63
|
+
skip_confirmation!
|
64
|
+
skip_approval!
|
65
|
+
end
|
66
|
+
|
67
|
+
def approve!
|
68
|
+
self.is_approved = true
|
69
|
+
self.approval_token = nil
|
70
|
+
send_confirmation_instructions
|
71
|
+
save(:validate => false)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Verifies whether a user is confirmed or not
|
75
|
+
def approved?
|
76
|
+
self.is_approved
|
77
|
+
end
|
78
|
+
|
79
|
+
def skip_approval!
|
80
|
+
self.is_approved = true
|
81
|
+
@skip_approval = true
|
82
|
+
end
|
83
|
+
|
84
|
+
# Send confirmation instructions by email
|
85
|
+
def send_approval_instructions
|
86
|
+
generate_approval_token if self.approval_token.nil?
|
87
|
+
::DeviseMailer.deliver_approval_instructions(self)
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
# Callback to overwrite if confirmation is required or not.
|
93
|
+
def confirmation_required?
|
94
|
+
!@skip_confirmation
|
95
|
+
end
|
96
|
+
|
97
|
+
def approval_required?
|
98
|
+
!@skip_approval
|
99
|
+
end
|
100
|
+
|
101
|
+
# Checks if the confirmation for the user is within the limit time.
|
102
|
+
# We do this by calculating if the difference between today and the
|
103
|
+
# confirmation sent date does not exceed the confirm in time configured.
|
104
|
+
# Confirm_in is a model configuration, must always be an integer value.
|
105
|
+
#
|
106
|
+
# Example:
|
107
|
+
#
|
108
|
+
# # confirm_within = 1.day and confirmation_sent_at = today
|
109
|
+
# confirmation_period_valid? # returns true
|
110
|
+
#
|
111
|
+
# # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
|
112
|
+
# confirmation_period_valid? # returns true
|
113
|
+
#
|
114
|
+
# # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
|
115
|
+
# confirmation_period_valid? # returns false
|
116
|
+
#
|
117
|
+
# # confirm_within = 0.days
|
118
|
+
# confirmation_period_valid? # will always return false
|
119
|
+
#
|
120
|
+
def confirmation_period_valid?
|
121
|
+
confirmation_sent_at && confirmation_sent_at.utc >= self.class.confirm_within.ago
|
122
|
+
end
|
123
|
+
|
124
|
+
# Checks whether the record is confirmed or not, yielding to the block
|
125
|
+
# if it's already confirmed, otherwise adds an error to email.
|
126
|
+
def unless_confirmed
|
127
|
+
unless confirmed?
|
128
|
+
yield
|
129
|
+
else
|
130
|
+
self.class.add_error_on(self, :email, :already_confirmed)
|
131
|
+
false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Generates a new random token for confirmation, and stores the time
|
136
|
+
# this token is being generated
|
137
|
+
def generate_confirmation_token
|
138
|
+
self.confirmed_at = nil
|
139
|
+
self.confirmation_token = Devise.friendly_token
|
140
|
+
self.confirmation_sent_at = Time.now.utc
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_approval_token
|
144
|
+
self.is_approved = false
|
145
|
+
self.approval_token = Devise.friendly_token
|
146
|
+
self.approval_sent_at = Time.now.utc
|
147
|
+
end
|
148
|
+
|
149
|
+
module ClassMethods
|
150
|
+
# Attempt to find a user by it's email. If a record is found, send new
|
151
|
+
# confirmation instructions to it. If not user is found, returns a new user
|
152
|
+
# with an email not found error.
|
153
|
+
# Options must contain the user email
|
154
|
+
def send_confirmation_instructions(attributes={})
|
155
|
+
confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
156
|
+
confirmable.resend_confirmation_token unless confirmable.new_record?
|
157
|
+
confirmable
|
158
|
+
end
|
159
|
+
|
160
|
+
# Find a user by it's confirmation token and try to confirm it.
|
161
|
+
# If no user is found, returns a new user with an error.
|
162
|
+
# If the user is already confirmed, create an error for the user
|
163
|
+
# Options must have the confirmation_token
|
164
|
+
def confirm_by_token(confirmation_token)
|
165
|
+
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
166
|
+
confirmable.confirm! unless confirmable.new_record?
|
167
|
+
confirmable
|
168
|
+
end
|
169
|
+
|
170
|
+
Devise::Models.config(self, :confirm_within)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'test/unit/helpers/approvable_helper_test'
|
3
|
+
|
4
|
+
class ApprovableTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
setup_mailer
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'should never generate the same confirmation token for different users' do
|
11
|
+
confirmation_tokens = []
|
12
|
+
3.times do
|
13
|
+
token = create_user.send_confirmation_instructions
|
14
|
+
assert !confirmation_tokens.include?(token)
|
15
|
+
confirmation_tokens << token
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'should confirm a user by updating confirmed at' do
|
20
|
+
user = create_user
|
21
|
+
assert_nil user.confirmed_at
|
22
|
+
assert user.confirm!
|
23
|
+
assert_not_nil user.confirmed_at
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'should clear confirmation token while confirming a user' do
|
27
|
+
user = create_user
|
28
|
+
user.confirm!
|
29
|
+
assert_nil user.confirmation_token
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'should verify whether a user is confirmed or not' do
|
33
|
+
assert_not new_user.confirmed?
|
34
|
+
user = create_user
|
35
|
+
assert_not user.confirmed?
|
36
|
+
user.confirm!
|
37
|
+
assert user.confirmed?
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'should not confirm a user already confirmed' do
|
41
|
+
user = create_user
|
42
|
+
assert user.confirm!
|
43
|
+
assert_nil user.errors[:email]
|
44
|
+
|
45
|
+
assert_not user.confirm!
|
46
|
+
assert_match /already confirmed/, user.errors[:email]
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'should return a new record with errors when a invalid token is given' do
|
50
|
+
confirmed_user = User.confirm_by_token('invalid_confirmation_token')
|
51
|
+
assert confirmed_user.new_record?
|
52
|
+
assert_match /invalid/, confirmed_user.errors[:confirmation_token]
|
53
|
+
end
|
54
|
+
|
55
|
+
test 'should return a new record with errors when a blank token is given' do
|
56
|
+
confirmed_user = User.confirm_by_token('')
|
57
|
+
assert confirmed_user.new_record?
|
58
|
+
assert_match /blank/, confirmed_user.errors[:confirmation_token]
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'should authenticate a confirmed user' do
|
62
|
+
user = create_user
|
63
|
+
user.confirm!
|
64
|
+
authenticated_user = User.authenticate(:email => user.email, :password => user.password)
|
65
|
+
assert_equal authenticated_user, user
|
66
|
+
end
|
67
|
+
|
68
|
+
test 'should not send confirmation when trying to save an invalid user' do
|
69
|
+
assert_email_not_sent do
|
70
|
+
user = new_user
|
71
|
+
user.stubs(:valid?).returns(false)
|
72
|
+
user.save
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
test 'should not generate a new token neither send e-mail if skip_confirmation! is invoked' do
|
77
|
+
user = new_user
|
78
|
+
user.skip_confirmation!
|
79
|
+
|
80
|
+
assert_email_not_sent do
|
81
|
+
user.save!
|
82
|
+
assert_nil user.confirmation_token
|
83
|
+
assert_not_nil user.confirmed_at
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
test 'should find a user to send confirmation instructions' do
|
88
|
+
user = create_user
|
89
|
+
confirmation_user = User.send_confirmation_instructions(:email => user.email)
|
90
|
+
assert_equal confirmation_user, user
|
91
|
+
end
|
92
|
+
|
93
|
+
test 'should return a new user if no email was found' do
|
94
|
+
confirmation_user = User.send_confirmation_instructions(:email => "invalid@email.com")
|
95
|
+
assert confirmation_user.new_record?
|
96
|
+
end
|
97
|
+
|
98
|
+
test 'should add error to new user email if no email was found' do
|
99
|
+
confirmation_user = User.send_confirmation_instructions(:email => "invalid@email.com")
|
100
|
+
assert confirmation_user.errors[:email]
|
101
|
+
assert_equal 'not found', confirmation_user.errors[:email]
|
102
|
+
end
|
103
|
+
|
104
|
+
test 'should send email instructions for the user confirm it\'s email' do
|
105
|
+
user = create_user
|
106
|
+
assert_email_sent do
|
107
|
+
User.send_confirmation_instructions(:email => user.email)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
test 'should always have confirmation token when email is sent' do
|
112
|
+
user = new_user
|
113
|
+
user.instance_eval { def confirmation_required?; false end }
|
114
|
+
user.save
|
115
|
+
user.send_confirmation_instructions
|
116
|
+
assert_not_nil user.confirmation_token
|
117
|
+
end
|
118
|
+
|
119
|
+
test 'should not resend email instructions if the user change his email' do
|
120
|
+
user = create_user
|
121
|
+
user.email = 'new_test@example.com'
|
122
|
+
assert_email_not_sent do
|
123
|
+
user.save!
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
test 'should not reset confirmation status or token when updating email' do
|
128
|
+
user = create_user
|
129
|
+
user.confirm!
|
130
|
+
user.email = 'new_test@example.com'
|
131
|
+
user.save!
|
132
|
+
|
133
|
+
user.reload
|
134
|
+
assert user.confirmed?
|
135
|
+
assert_nil user.confirmation_token
|
136
|
+
end
|
137
|
+
|
138
|
+
test 'should not be able to send instructions if the user is already confirmed' do
|
139
|
+
user = create_user
|
140
|
+
user.confirm!
|
141
|
+
assert_not user.resend_confirmation_token
|
142
|
+
assert user.confirmed?
|
143
|
+
assert_equal 'already confirmed', user.errors[:email]
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'confirm time should fallback to devise confirm in default configuration' do
|
147
|
+
swap Devise, :confirm_within => 1.day do
|
148
|
+
user = new_user
|
149
|
+
user.confirmation_sent_at = 2.days.ago
|
150
|
+
assert_not user.active?
|
151
|
+
|
152
|
+
Devise.confirm_within = 3.days
|
153
|
+
assert user.active?
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
test 'should be active when confirmation sent at is not overpast' do
|
158
|
+
swap Devise, :confirm_within => 5.days do
|
159
|
+
Devise.confirm_within = 5.days
|
160
|
+
user = create_user
|
161
|
+
|
162
|
+
user.confirmation_sent_at = 4.days.ago
|
163
|
+
assert user.active?
|
164
|
+
|
165
|
+
user.confirmation_sent_at = 5.days.ago
|
166
|
+
assert_not user.active?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
test 'should be active when already confirmed' do
|
171
|
+
user = create_user
|
172
|
+
assert_not user.confirmed?
|
173
|
+
assert_not user.active?
|
174
|
+
|
175
|
+
user.confirm!
|
176
|
+
assert user.confirmed?
|
177
|
+
assert user.active?
|
178
|
+
end
|
179
|
+
|
180
|
+
test 'should not be active when confirm in is zero' do
|
181
|
+
Devise.confirm_within = 0.days
|
182
|
+
user = create_user
|
183
|
+
user.confirmation_sent_at = Date.today
|
184
|
+
assert_not user.reload.active?
|
185
|
+
end
|
186
|
+
|
187
|
+
test 'should not be active without confirmation' do
|
188
|
+
user = create_user
|
189
|
+
user.confirmation_sent_at = nil
|
190
|
+
user.save
|
191
|
+
assert_not user.reload.active?
|
192
|
+
end
|
193
|
+
|
194
|
+
test 'should be active without confirmation when confirmation is not required' do
|
195
|
+
user = create_user
|
196
|
+
user.instance_eval { def confirmation_required?; false end }
|
197
|
+
user.confirmation_sent_at = nil
|
198
|
+
user.save
|
199
|
+
assert user.reload.active?
|
200
|
+
end
|
201
|
+
|
202
|
+
# Approvable Tests
|
203
|
+
|
204
|
+
test 'should generate approval token after creating a record' do
|
205
|
+
assert_nil new_user.approval_token
|
206
|
+
assert_not_nil create_user.approval_token
|
207
|
+
end
|
208
|
+
|
209
|
+
test 'should clear approval token after approving a user' do
|
210
|
+
user = create_user
|
211
|
+
user.approve!
|
212
|
+
assert_nil user.approval_token
|
213
|
+
end
|
214
|
+
|
215
|
+
test 'should verify whether a user is approved or not' do
|
216
|
+
assert_not new_user.approved?
|
217
|
+
user = create_user
|
218
|
+
assert_not user.approved?
|
219
|
+
user.approve!
|
220
|
+
assert user.approved?
|
221
|
+
end
|
222
|
+
|
223
|
+
test 'should not generate a new token neither send e-mail if skip_approval! is invoked' do
|
224
|
+
user = new_user
|
225
|
+
user.skip_approval!
|
226
|
+
|
227
|
+
assert_email_not_sent do
|
228
|
+
user.save!
|
229
|
+
assert_nil user.approval_token
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
test 'should not generate a new token neither send e-mail if skip_confirm_and_approve! is invoked' do
|
234
|
+
user = new_user
|
235
|
+
user.skip_confirm_and_approve!
|
236
|
+
|
237
|
+
assert_email_not_sent do
|
238
|
+
user.save!
|
239
|
+
assert_nil user.confirmation_token
|
240
|
+
assert_nil user.approval_token
|
241
|
+
assert user.approved?
|
242
|
+
assert_not_nil user.confirmed_at
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<p>Someone has registered for a membership.</p>
|
2
|
+
|
3
|
+
<p>Details:
|
4
|
+
<%= "<br />First Name: #{@resource.first_name}" if !@resource.first_name.nil? %>
|
5
|
+
<%= "<br />Last Name: #{@resource.last_name}" if !@resource.last_name.nil? %>
|
6
|
+
<%= "<br />E-Mail: #{@resource.email}" if !@resource.email.nil? %>
|
7
|
+
<%= "<br />Phone Number: #{@resource.phone}" if !@resource.phone.nil? %>
|
8
|
+
<%= "<br />Bio: #{@resource.bio}" if !@resource.bio.nil? %>
|
9
|
+
|
10
|
+
<p>If you would like to approve this person click the following link. Clicking the link will approve the new user and send the user a confirmation email.</p>
|
11
|
+
<p><%= link_to "Approve account for #{@resource.email} #{approvals_url(@resource.approval_token)}", approvals_url(@resource.approval_token) %></p>
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise-approvable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Egg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: shoulda
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jeweler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: adds feature to devise
|
84
|
+
email: eggie5@gmail.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files:
|
88
|
+
- README
|
89
|
+
files:
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- README
|
93
|
+
- Rakefile
|
94
|
+
- VERSION
|
95
|
+
- config/initializers/devise.rb
|
96
|
+
- device-approvable.gemspec
|
97
|
+
- lib/approvable.rb
|
98
|
+
- lib/approvable_mailer.rb
|
99
|
+
- test/approvable_test.rb
|
100
|
+
- views/devise_mailer/approval_instructions.html.erb
|
101
|
+
homepage: http://github.com/eggie5/devise-approvable
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.2.1
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: Oh so perfect
|
125
|
+
test_files: []
|