devise_invitable 0.1.0
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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/app/controllers/invitations_controller.rb +48 -0
- data/app/views/devise_mailer/invitation.html.erb +8 -0
- data/app/views/invitations/edit.html.erb +14 -0
- data/app/views/invitations/new.html.erb +10 -0
- data/devise_invitable.gemspec +121 -0
- data/init.rb +1 -0
- data/lib/devise/controllers/url_helpers.rb +20 -0
- data/lib/devise/models/invitable.rb +143 -0
- data/lib/devise_invitable.rb +14 -0
- data/lib/devise_invitable/locales/en.yml +5 -0
- data/lib/devise_invitable/mailer.rb +9 -0
- data/lib/devise_invitable/rails.rb +3 -0
- data/lib/devise_invitable/routes.rb +28 -0
- data/lib/devise_invitable/schema.rb +11 -0
- data/rails/init.rb +1 -0
- data/test/integration/invitable_test.rb +122 -0
- data/test/integration_tests_helper.rb +38 -0
- data/test/mailers/invitation_test.rb +62 -0
- data/test/model_tests_helper.rb +59 -0
- data/test/models/invitable_test.rb +164 -0
- data/test/models_test.rb +35 -0
- data/test/rails_app/app/controllers/admins_controller.rb +6 -0
- data/test/rails_app/app/controllers/application_controller.rb +10 -0
- data/test/rails_app/app/controllers/home_controller.rb +4 -0
- data/test/rails_app/app/controllers/users_controller.rb +12 -0
- data/test/rails_app/app/helpers/application_helper.rb +3 -0
- data/test/rails_app/app/models/user.rb +4 -0
- data/test/rails_app/app/views/home/index.html.erb +0 -0
- data/test/rails_app/config/boot.rb +110 -0
- data/test/rails_app/config/database.yml +22 -0
- data/test/rails_app/config/environment.rb +44 -0
- data/test/rails_app/config/environments/development.rb +17 -0
- data/test/rails_app/config/environments/production.rb +28 -0
- data/test/rails_app/config/environments/test.rb +28 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/inflections.rb +2 -0
- data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
- data/test/rails_app/config/initializers/session_store.rb +15 -0
- data/test/rails_app/config/routes.rb +3 -0
- data/test/rails_app/vendor/plugins/devise_invitable/init.rb +1 -0
- data/test/routes_test.rb +20 -0
- data/test/test_helper.rb +58 -0
- metadata +156 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Sergio Cambra
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= devise_invitable
|
2
|
+
|
3
|
+
It adds support for send invitations by email (it requires to be authenticated) and accept the invitation setting the password.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Sergio Cambra. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "devise_invitable"
|
8
|
+
gem.summary = %Q{An invitation strategy for devise}
|
9
|
+
gem.description = %Q{It adds support for send invitations by email (it requires to be authenticated) and accept the invitation setting the password}
|
10
|
+
gem.email = "sergio@entrecables.com"
|
11
|
+
gem.homepage = "http://github.com/scambra/devise_invitable"
|
12
|
+
gem.authors = ["Sergio Cambra"]
|
13
|
+
gem.add_development_dependency 'mocha'
|
14
|
+
gem.add_development_dependency 'webrat'
|
15
|
+
gem.add_dependency 'devise', '>= 0.7.1'
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/*_test.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "devise_invitable #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class InvitationsController < ApplicationController
|
2
|
+
include Devise::Controllers::Helpers
|
3
|
+
|
4
|
+
before_filter :authenticate_resource!, :only => [:new, :create]
|
5
|
+
before_filter :require_no_authentication, :only => [:edit, :update]
|
6
|
+
|
7
|
+
# GET /resource/invitation/new
|
8
|
+
def new
|
9
|
+
build_resource
|
10
|
+
render_with_scope :new
|
11
|
+
end
|
12
|
+
|
13
|
+
# POST /resource/invitation
|
14
|
+
def create
|
15
|
+
self.resource = resource_class.send_invitation(params[resource_name])
|
16
|
+
|
17
|
+
if resource.errors.empty?
|
18
|
+
set_flash_message :success, :send_invitation
|
19
|
+
redirect_to after_sign_in_path_for(resource_name)
|
20
|
+
else
|
21
|
+
render_with_scope :new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# GET /resource/invitation/edit?invitation_token=abcdef
|
26
|
+
def edit
|
27
|
+
self.resource = resource_class.new
|
28
|
+
resource.invitation_token = params[:invitation_token]
|
29
|
+
render_with_scope :edit
|
30
|
+
end
|
31
|
+
|
32
|
+
# PUT /resource/invitation
|
33
|
+
def update
|
34
|
+
self.resource = resource_class.accept_invitation!(params[resource_name])
|
35
|
+
|
36
|
+
if resource.errors.empty?
|
37
|
+
set_flash_message :success, :updated
|
38
|
+
sign_in_and_redirect(resource_name, resource)
|
39
|
+
else
|
40
|
+
render_with_scope :edit
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
def authenticate_resource!
|
46
|
+
authenticate!(resource_name)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Hello <%= @resource.email %>!
|
2
|
+
|
3
|
+
Someone has invited you to <%= root_url %>, you can accept it through the link below.
|
4
|
+
|
5
|
+
<%= link_to 'Accept invitation', edit_invitation_url(@resource, :invitation_token => @resource.invitation_token) %>
|
6
|
+
|
7
|
+
If you don't want to accept the invitation, please ignore this email.
|
8
|
+
Your account won't be created until you access the link above and set your password.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h2>Set your password</h2>
|
2
|
+
|
3
|
+
<% form_for resource_name, resource, :url => invitation_path(resource_name), :html => { :method => :put } do |f| %>
|
4
|
+
<%= f.error_messages %>
|
5
|
+
<%= f.hidden_field :invitation_token %>
|
6
|
+
|
7
|
+
<p><%= f.label :password %></p>
|
8
|
+
<p><%= f.password_field :password %></p>
|
9
|
+
|
10
|
+
<p><%= f.label :password_confirmation %></p>
|
11
|
+
<p><%= f.password_field :password_confirmation %></p>
|
12
|
+
|
13
|
+
<p><%= f.submit "Set my password" %></p>
|
14
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<h2>Send invitation</h2>
|
2
|
+
|
3
|
+
<% form_for resource_name, resource, :url => invitation_path(resource_name) do |f| %>
|
4
|
+
<%= f.error_messages %>
|
5
|
+
|
6
|
+
<p><%= f.label :email %></p>
|
7
|
+
<p><%= f.text_field :email %></p>
|
8
|
+
|
9
|
+
<p><%= f.submit "Send an invitation" %></p>
|
10
|
+
<% end %>
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{devise_invitable}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Sergio Cambra"]
|
12
|
+
s.date = %q{2009-12-10}
|
13
|
+
s.description = %q{It adds support for send invitations by email (it requires to be authenticated) and accept the invitation setting the password}
|
14
|
+
s.email = %q{sergio@entrecables.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"app/controllers/invitations_controller.rb",
|
27
|
+
"app/views/devise_mailer/invitation.html.erb",
|
28
|
+
"app/views/invitations/edit.html.erb",
|
29
|
+
"app/views/invitations/new.html.erb",
|
30
|
+
"devise_invitable.gemspec",
|
31
|
+
"init.rb",
|
32
|
+
"lib/devise/controllers/url_helpers.rb",
|
33
|
+
"lib/devise/models/invitable.rb",
|
34
|
+
"lib/devise_invitable.rb",
|
35
|
+
"lib/devise_invitable/locales/en.yml",
|
36
|
+
"lib/devise_invitable/mailer.rb",
|
37
|
+
"lib/devise_invitable/rails.rb",
|
38
|
+
"lib/devise_invitable/routes.rb",
|
39
|
+
"lib/devise_invitable/schema.rb",
|
40
|
+
"rails/init.rb",
|
41
|
+
"test/integration/invitable_test.rb",
|
42
|
+
"test/integration_tests_helper.rb",
|
43
|
+
"test/mailers/invitation_test.rb",
|
44
|
+
"test/model_tests_helper.rb",
|
45
|
+
"test/models/invitable_test.rb",
|
46
|
+
"test/models_test.rb",
|
47
|
+
"test/rails_app/app/controllers/admins_controller.rb",
|
48
|
+
"test/rails_app/app/controllers/application_controller.rb",
|
49
|
+
"test/rails_app/app/controllers/home_controller.rb",
|
50
|
+
"test/rails_app/app/controllers/users_controller.rb",
|
51
|
+
"test/rails_app/app/helpers/application_helper.rb",
|
52
|
+
"test/rails_app/app/models/user.rb",
|
53
|
+
"test/rails_app/app/views/home/index.html.erb",
|
54
|
+
"test/rails_app/config/boot.rb",
|
55
|
+
"test/rails_app/config/database.yml",
|
56
|
+
"test/rails_app/config/environment.rb",
|
57
|
+
"test/rails_app/config/environments/development.rb",
|
58
|
+
"test/rails_app/config/environments/production.rb",
|
59
|
+
"test/rails_app/config/environments/test.rb",
|
60
|
+
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
61
|
+
"test/rails_app/config/initializers/inflections.rb",
|
62
|
+
"test/rails_app/config/initializers/new_rails_defaults.rb",
|
63
|
+
"test/rails_app/config/initializers/session_store.rb",
|
64
|
+
"test/rails_app/config/routes.rb",
|
65
|
+
"test/rails_app/vendor/plugins/devise_invitable/init.rb",
|
66
|
+
"test/routes_test.rb",
|
67
|
+
"test/test_helper.rb"
|
68
|
+
]
|
69
|
+
s.homepage = %q{http://github.com/scambra/devise_invitable}
|
70
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
71
|
+
s.require_paths = ["lib"]
|
72
|
+
s.rubygems_version = %q{1.3.5}
|
73
|
+
s.summary = %q{An invitation strategy for devise}
|
74
|
+
s.test_files = [
|
75
|
+
"test/model_tests_helper.rb",
|
76
|
+
"test/integration_tests_helper.rb",
|
77
|
+
"test/models_test.rb",
|
78
|
+
"test/mailers/invitation_test.rb",
|
79
|
+
"test/routes_test.rb",
|
80
|
+
"test/integration/invitable_test.rb",
|
81
|
+
"test/models/invitable_test.rb",
|
82
|
+
"test/test_helper.rb",
|
83
|
+
"test/rails_app/app/controllers/application_controller.rb",
|
84
|
+
"test/rails_app/app/controllers/admins_controller.rb",
|
85
|
+
"test/rails_app/app/controllers/home_controller.rb",
|
86
|
+
"test/rails_app/app/controllers/users_controller.rb",
|
87
|
+
"test/rails_app/app/models/user.rb",
|
88
|
+
"test/rails_app/app/helpers/application_helper.rb",
|
89
|
+
"test/rails_app/config/routes.rb",
|
90
|
+
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
91
|
+
"test/rails_app/config/initializers/new_rails_defaults.rb",
|
92
|
+
"test/rails_app/config/initializers/session_store.rb",
|
93
|
+
"test/rails_app/config/initializers/inflections.rb",
|
94
|
+
"test/rails_app/config/environments/test.rb",
|
95
|
+
"test/rails_app/config/environments/development.rb",
|
96
|
+
"test/rails_app/config/environments/production.rb",
|
97
|
+
"test/rails_app/config/environment.rb",
|
98
|
+
"test/rails_app/config/boot.rb",
|
99
|
+
"test/rails_app/vendor/plugins/devise_invitable/init.rb"
|
100
|
+
]
|
101
|
+
|
102
|
+
if s.respond_to? :specification_version then
|
103
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
104
|
+
s.specification_version = 3
|
105
|
+
|
106
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
107
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
108
|
+
s.add_development_dependency(%q<webrat>, [">= 0"])
|
109
|
+
s.add_runtime_dependency(%q<devise>, [">= 0.7.1"])
|
110
|
+
else
|
111
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
112
|
+
s.add_dependency(%q<webrat>, [">= 0"])
|
113
|
+
s.add_dependency(%q<devise>, [">= 0.7.1"])
|
114
|
+
end
|
115
|
+
else
|
116
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
117
|
+
s.add_dependency(%q<webrat>, [">= 0"])
|
118
|
+
s.add_dependency(%q<devise>, [">= 0.7.1"])
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rails/init'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Devise::Controllers::UrlHelpers.module_eval do
|
2
|
+
[:path, :url].each do |path_or_url|
|
3
|
+
[nil, :new_, :edit_].each do |action|
|
4
|
+
class_eval <<-URL_HELPERS
|
5
|
+
def #{action}invitation_#{path_or_url}(resource, *args)
|
6
|
+
resource = case resource
|
7
|
+
when Symbol, String
|
8
|
+
resource
|
9
|
+
when Class
|
10
|
+
resource.name.underscore
|
11
|
+
else
|
12
|
+
resource.class.name.underscore
|
13
|
+
end
|
14
|
+
|
15
|
+
send("#{action}\#{resource}_invitation_#{path_or_url}", *args)
|
16
|
+
end
|
17
|
+
URL_HELPERS
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
|
4
|
+
# Invitable is responsible to send emails with invitations.
|
5
|
+
# When an invitation is sent to an email, an account is created for it.
|
6
|
+
# An invitation has a link to set the password, as reset password from recoverable.
|
7
|
+
#
|
8
|
+
# Configuration:
|
9
|
+
#
|
10
|
+
# invite_for: the time you want the user will have to confirm the account after
|
11
|
+
# is invited. When invite_for is zero, the invitation won't expire.
|
12
|
+
# By default invite_for is 0.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# User.find(1).invited? # true/false
|
17
|
+
# User.send_invitation(:email => 'someone@example.com') # send invitation
|
18
|
+
# User.accept_invitation!(:invitation_token => '...') # accept invitation with a token
|
19
|
+
# User.find(1).accept_invitation! # accept invitation
|
20
|
+
# User.find(1).reset_invitation! # reset invitation status and send invitation again
|
21
|
+
module Invitable
|
22
|
+
|
23
|
+
def self.included(base)
|
24
|
+
base.class_eval do
|
25
|
+
extend ClassMethods
|
26
|
+
callbacks = []
|
27
|
+
callbacks.concat before_create_callback_chain.select {|c| c.method == :generate_confirmation_token}
|
28
|
+
callbacks.concat after_create_callback_chain.select {|c| c.method == :send_confirmation_instructions}
|
29
|
+
callbacks.each do |c|
|
30
|
+
c.options[:unless] = lambda{|r| r.class.devise_modules.include?(:invitable) && r.invitation_token}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Accept an invitation by clearing invitation token and confirming it if model
|
36
|
+
# is confirmable
|
37
|
+
def accept_invitation!
|
38
|
+
if self.invited?
|
39
|
+
self.invitation_token = nil
|
40
|
+
if self.class.devise_modules.include? :confirmable
|
41
|
+
self.confirm!
|
42
|
+
else
|
43
|
+
save
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Verifies whether a user has been invited or not
|
49
|
+
def invited?
|
50
|
+
!new_record? && !invitation_token.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Send invitation by email
|
54
|
+
def send_invitation
|
55
|
+
::DeviseMailer.deliver_invitation(self)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Reset invitation token and send invitation again
|
59
|
+
def reset_invitation!
|
60
|
+
if new_record? || invited?
|
61
|
+
generate_invitation_token
|
62
|
+
save(false)
|
63
|
+
send_invitation
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Verify whether a invitation is active or not. If the user has been
|
68
|
+
# invited, we need to calculate if the invitation time has not expired
|
69
|
+
# for this user, in other words, if the invitation is still valid.
|
70
|
+
def valid_invitation?
|
71
|
+
invited? && invitation_period_valid?
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Checks if the invitation for the user is within the limit time.
|
77
|
+
# We do this by calculating if the difference between today and the
|
78
|
+
# invitation sent date does not exceed the invite for time configured.
|
79
|
+
# Invite_for is a model configuration, must always be an integer value.
|
80
|
+
#
|
81
|
+
# Example:
|
82
|
+
#
|
83
|
+
# # invite_for = 1.day and invitation_sent_at = today
|
84
|
+
# invitation_period_valid? # returns true
|
85
|
+
#
|
86
|
+
# # invite_for = 5.days and invitation_sent_at = 4.days.ago
|
87
|
+
# invitation_period_valid? # returns true
|
88
|
+
#
|
89
|
+
# # invite_for = 5.days and invitation_sent_at = 5.days.ago
|
90
|
+
# invitation_period_valid? # returns false
|
91
|
+
#
|
92
|
+
# # invite_for = nil
|
93
|
+
# invitation_period_valid? # will always return true
|
94
|
+
#
|
95
|
+
def invitation_period_valid?
|
96
|
+
invitation_sent_at && (self.class.invite_for.to_i.zero? || invitation_sent_at.utc >= self.class.invite_for.ago)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Generates a new random token for invitation, and stores the time
|
100
|
+
# this token is being generated
|
101
|
+
def generate_invitation_token
|
102
|
+
self.invitation_token = Devise.friendly_token
|
103
|
+
self.invitation_sent_at = Time.now.utc
|
104
|
+
end
|
105
|
+
|
106
|
+
module ClassMethods
|
107
|
+
# Attempt to find a user by it's email. If a record is not found, create a new
|
108
|
+
# user and send invitation to it. If user is found, returns the user with an
|
109
|
+
# email already exists error.
|
110
|
+
# Options must contain the user email
|
111
|
+
def send_invitation(attributes={})
|
112
|
+
invitable = find_or_initialize_by_email(attributes[:email])
|
113
|
+
if invitable.email.blank?
|
114
|
+
invitable.errors.add(:email, :blank)
|
115
|
+
elsif invitable.new_record? || invitable.invited?
|
116
|
+
invitable.reset_invitation!
|
117
|
+
else
|
118
|
+
invitable.errors.add(:email, :already_exits, :default => 'already exists')
|
119
|
+
end
|
120
|
+
invitable
|
121
|
+
end
|
122
|
+
|
123
|
+
# Attempt to find a user by it's invitation_token to set it's password.
|
124
|
+
# If a user is found, reset it's password and automatically try saving
|
125
|
+
# the record. If not user is found, returns a new user containing an
|
126
|
+
# error in invitation_token attribute.
|
127
|
+
# Attributes must contain invitation_token, password and confirmation
|
128
|
+
def accept_invitation!(attributes={})
|
129
|
+
invitable = find_or_initialize_with_error_by(:invitation_token, attributes[:invitation_token])
|
130
|
+
invitable.errors.add(:invitation_token, :invalid) if attributes[:invitation_token] && !invitable.new_record? && !invitable.valid_invitation?
|
131
|
+
if invitable.errors.empty?
|
132
|
+
invitable.password = attributes[:password]
|
133
|
+
invitable.password_confirmation = attributes[:password_confirmation]
|
134
|
+
invitable.accept_invitation! if invitable.valid?
|
135
|
+
end
|
136
|
+
invitable
|
137
|
+
end
|
138
|
+
|
139
|
+
Devise::Models.config(self, :invite_for)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|