devise_certifiable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE +19 -0
  4. data/README.rdoc +53 -0
  5. data/Rakefile +26 -0
  6. data/app/controllers/devise/certifications_controller.rb +34 -0
  7. data/app/views/devise/certifications/edit.html.erb +14 -0
  8. data/app/views/devise/mailer/certification_request.html.erb +8 -0
  9. data/config/locales/en.yml +17 -0
  10. data/devise_certifiable.gemspec +25 -0
  11. data/lib/devise_certifiable.rb +13 -0
  12. data/lib/devise_certifiable/controllers/helpers.rb +7 -0
  13. data/lib/devise_certifiable/controllers/url_helpers.rb +24 -0
  14. data/lib/devise_certifiable/mailer.rb +10 -0
  15. data/lib/devise_certifiable/model.rb +98 -0
  16. data/lib/devise_certifiable/rails.rb +12 -0
  17. data/lib/devise_certifiable/routes.rb +10 -0
  18. data/lib/devise_certifiable/schema.rb +12 -0
  19. data/lib/devise_certifiable/version.rb +3 -0
  20. data/lib/generators/active_record/devise_certifiable_generator.rb +13 -0
  21. data/lib/generators/active_record/templates/migration.rb +18 -0
  22. data/lib/generators/devise_certifiable/devise_certifiable_generator.rb +16 -0
  23. data/lib/generators/devise_certifiable/install_generator.rb +11 -0
  24. data/test/controllers/url_helpers_test.rb +34 -0
  25. data/test/generators/active_record_generator_test.rb +24 -0
  26. data/test/generators/devise_certifiable_generator_test.rb +27 -0
  27. data/test/generators/install_generator_test.rb +15 -0
  28. data/test/integration/certification_test.rb +80 -0
  29. data/test/mailers/certification_request_test.rb +63 -0
  30. data/test/models/certifiable_test.rb +172 -0
  31. data/test/models_test.rb +26 -0
  32. data/test/orm/active_record.rb +4 -0
  33. data/test/rails_app/Rakefile +10 -0
  34. data/test/rails_app/app/active_record/user.rb +7 -0
  35. data/test/rails_app/app/controllers/application_controller.rb +3 -0
  36. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  37. data/test/rails_app/app/controllers/users_controller.rb +12 -0
  38. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  39. data/test/rails_app/app/models/monster.rb +5 -0
  40. data/test/rails_app/app/views/home/index.html.erb +1 -0
  41. data/test/rails_app/app/views/layouts/application.html.erb +20 -0
  42. data/test/rails_app/app/views/users/index.html.erb +1 -0
  43. data/test/rails_app/config.ru +4 -0
  44. data/test/rails_app/config/application.rb +29 -0
  45. data/test/rails_app/config/boot.rb +11 -0
  46. data/test/rails_app/config/database.yml +18 -0
  47. data/test/rails_app/config/environment.rb +5 -0
  48. data/test/rails_app/config/environments/development.rb +22 -0
  49. data/test/rails_app/config/environments/production.rb +33 -0
  50. data/test/rails_app/config/environments/test.rb +33 -0
  51. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  52. data/test/rails_app/config/initializers/devise.rb +179 -0
  53. data/test/rails_app/config/initializers/inflections.rb +2 -0
  54. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  55. data/test/rails_app/config/routes.rb +6 -0
  56. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +17 -0
  57. data/test/rails_app/lib/shared_user.rb +7 -0
  58. data/test/rails_app/script/rails +6 -0
  59. data/test/routes_test.rb +11 -0
  60. data/test/support/assertions.rb +24 -0
  61. data/test/support/helpers.rb +39 -0
  62. data/test/support/integration.rb +59 -0
  63. data/test/support/locale/en.yml +4 -0
  64. data/test/test_helper.rb +20 -0
  65. metadata +203 -0
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in devise_certifiable.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'sqlite3'
8
+ gem "capybara"
9
+ gem "launchy"
10
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Luis Gracia
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ = devise_certifiable
2
+
3
+ Sign up certification strategy for devise[http://github.com/plataformatec/devise]. New sign up users need to be certified before they can sign in. After sign up an email is sent to the email address specified in the devise configuration option _config.mailer_sender_.
4
+
5
+ Devise_certifiable has been tested with Devise 1.2.1 and Rails 3.0.6 using ActiveRecord, but similar version should work as well (ie. Devise 1.2.x and Rails 3.0.x).
6
+
7
+ == Installation
8
+
9
+ rails generate devise_certifiable MODEL
10
+
11
+ will add _:certifiable_ to model _MODEL_ and create a migration file.
12
+
13
+ == Configuration
14
+
15
+ There are no configuration options at the moment.
16
+
17
+ === Controllers
18
+
19
+ By default devise_certifiable follows Devise authentication to allow certifications. You can customize how to authenticate for a certifier overriding _:authenticate_certifier!_ in _application_controller.rb_. For example using CanCan[https://github.com/ryanb/cancan]:
20
+
21
+ def authenticate_certifier!
22
+ authorize! :certify, User
23
+ end
24
+
25
+ === Views
26
+
27
+ You can customize the views and mails by doing:
28
+
29
+ rails generate devise_certifiable:install views
30
+
31
+ This will copy the views to app/views/devise.
32
+
33
+ === Localization
34
+
35
+ Localization can be customized by:
36
+
37
+ rails generate devise_certifiable:install
38
+
39
+ This will copy the locale file to your rails tree.
40
+
41
+ == Contributing to devise_certifiable
42
+
43
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
44
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
45
+ * Fork the project
46
+ * Start a feature/bugfix branch
47
+ * Commit and push until you are happy with your contribution
48
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
49
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
50
+
51
+ == Copyright
52
+
53
+ Copyright (c) 2011 Luis Gracia. See LICENSE for further details.
@@ -0,0 +1,26 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+
6
+ desc 'Default: run tests for all ORMs.'
7
+ task :default => :pre_commit
8
+
9
+ desc 'Run Devise tests for all ORMs.'
10
+ task :pre_commit do
11
+ Dir[File.join(File.dirname(__FILE__), 'test', 'orm', '*.rb')].each do |file|
12
+ orm = File.basename(file).split(".").first
13
+ # "Some day, my son, rake's inner wisdom will reveal itself. Until then,
14
+ # take this `system` -- may its brute force protect you well."
15
+ #exit 1 unless system "rake test DEVISE_ORM=#{orm}"
16
+ system "rake test DEVISE_ORM=#{orm}"
17
+ end
18
+ end
19
+
20
+ desc 'Run std unit tests.'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib'
23
+ test.libs << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
@@ -0,0 +1,34 @@
1
+ class Devise::CertificationsController < ApplicationController
2
+ include Devise::Controllers::InternalHelpers
3
+ before_filter :authenticate_certifier!
4
+
5
+ # GET /resource/certification/edit?certification_token=abcdef
6
+ def edit
7
+ self.resource = resource_class.find_resource_by_token(params[:certification_token])
8
+
9
+ if resource.errors.empty?
10
+ render_with_scope :edit
11
+ else
12
+ set_flash_message(:alert, :certification_token_invalid)
13
+ redirect_to self.resource
14
+ end
15
+ end
16
+
17
+ # PUT /resource/certification
18
+ def update
19
+ self.resource = resource_class.certify_by_token(params[resource_name][:certification_token], current_certifier)
20
+ params[resource_name].delete(:certification_token)
21
+ self.resource.update_attributes(params[resource_name])
22
+ if resource.errors.empty?
23
+ set_flash_message :notice, :certified
24
+ redirect_to self.resource
25
+ else
26
+ render_with_scope :edit
27
+ end
28
+ end
29
+
30
+ protected
31
+ def current_certifier
32
+ current_user
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ <h2><%= resource_name.capitalize %> Certification</h2>
2
+
3
+ <%= form_for(resource, :as => resource_name, :url => certification_path(resource_name), :html => { :method => :put }) do |f| %>
4
+ <%= devise_error_messages! %>
5
+
6
+ <table>
7
+ <tr>
8
+ <td><%= f.label :email %></td>
9
+ <td><%= f.label :email, resource.email %></td>
10
+ </tr>
11
+ </table>
12
+ <%= f.hidden_field :certification_token -%>
13
+ <p><%= f.submit "Certify" %></p>
14
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <p>Dear Admin,</p>
2
+
3
+ <p>The following user has requested access to the site:</p>
4
+ <table>
5
+ <tr><td>Email:</td><td><%= @resource.email %></td></tr>
6
+ </table>
7
+
8
+ <p><%= link_to 'Certify', edit_certification_url(@resource, :certification_token => @resource.certification_token) %></p>
@@ -0,0 +1,17 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ certification_authority_missing: '(certification authority) not specified'
5
+ already_certified: 'was already certified!'
6
+
7
+
8
+ devise:
9
+ failure:
10
+ :uncertified: 'Your account needs to be certified.'
11
+ mailer:
12
+ certification_request:
13
+ subject: 'Certification request'
14
+ certifications:
15
+ certification_token_invalid: 'The certification token provided is not valid!'
16
+ certified: 'Successfuly certified user'
17
+
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "devise_certifiable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "devise_certifiable"
7
+ s.version = DeviseCertifiable::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Luis Gracia"]
10
+ s.email = ["lgraval@gmail.com"]
11
+ s.homepage = "https://github.com/luisico/devise_certifiable"
12
+ s.summary = %q{Sign up certification strategy for devise}
13
+ s.description = %q{New sign ups need to be certified before they can sign in}
14
+
15
+ s.add_dependency('rails', '~> 3.0.0')
16
+ s.add_dependency('devise', '~> 1.2.0')
17
+
18
+ s.add_development_dependency('devise_invitable', '~> 0.4.0')
19
+ s.add_development_dependency('bundler', '~> 1.0.12')
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,13 @@
1
+ require 'devise'
2
+
3
+ require 'devise_certifiable/mailer'
4
+ require 'devise_certifiable/routes'
5
+ require 'devise_certifiable/schema'
6
+ require 'devise_certifiable/controllers/url_helpers'
7
+ require 'devise_certifiable/controllers/helpers'
8
+ require 'devise_certifiable/rails'
9
+
10
+ module Devise
11
+ end
12
+
13
+ Devise.add_module :certifiable, :model => 'devise_certifiable/model', :route => :certification, :controller => :certifications
@@ -0,0 +1,7 @@
1
+ module DeviseCertifiable::Controllers::Helpers
2
+ protected
3
+ def authenticate_certifier!
4
+ send(:"authenticate_#{resource_name}!", true)
5
+ end
6
+ end
7
+ ActionController::Base.send :include, DeviseCertifiable::Controllers::Helpers
@@ -0,0 +1,24 @@
1
+ module DeviseCertifiable
2
+ module Controllers
3
+ module UrlHelpers
4
+ [:path, :url].each do |path_or_url|
5
+ [nil, :edit_].each do |action|
6
+ class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
7
+ def #{action}certification_#{path_or_url}(resource, *args)
8
+ resource = case resource
9
+ when Symbol, String
10
+ resource
11
+ when Class
12
+ resource.name.underscore
13
+ else
14
+ resource.class.name.underscore
15
+ end
16
+
17
+ send("#{action}\#{resource}_certification_#{path_or_url}", *args)
18
+ end
19
+ URL_HELPERS
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module DeviseCertifiable
2
+ module Mailer
3
+ # Request certification from certification authority
4
+ def certification_request(record)
5
+ mail = setup_mail(record, :certification_request)
6
+ mail.to = mailer_sender(@devise_mapping)
7
+ return mail
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,98 @@
1
+ module Devise
2
+ module Models
3
+ module Certifiable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ belongs_to :certified_by, :polymorphic => true
8
+ before_create :generate_certification_token, :if => :certification_required?
9
+ after_create :request_certification, :if => :certification_required?
10
+ alias_method_chain :send_confirmation_instructions, :certification
11
+ end
12
+
13
+ def certify!(certification_authority)
14
+ unless_certified do
15
+ unless certification_authority.blank?
16
+ self.certification_token = nil
17
+ self.certified_at = Time.now
18
+ self.certified_by = certification_authority
19
+ save(:validate => false)
20
+ send_confirmation_instructions if confirmation_required?
21
+ else
22
+ self.errors.add(:certified_by, :certification_authority_missing)
23
+ false
24
+ end
25
+ end
26
+ end
27
+
28
+ def certified?
29
+ !!certified_at
30
+ end
31
+
32
+ # Deliver certification request to certification authority
33
+ def request_certification
34
+ if self.respond_to?(:invite!) && self.invitation_token.present?
35
+ certify!(self.invited_by)
36
+ else
37
+ generate_certification_token! if self.certification_token.nil?
38
+ ::Devise.mailer.certification_request(self).deliver
39
+ end
40
+ end
41
+
42
+ def active_for_authentication?
43
+ super && certified?
44
+ end
45
+
46
+ def inactive_message
47
+ !certified? ? :uncertified : super
48
+ end
49
+ protected
50
+
51
+ def certification_required?
52
+ !certified?
53
+ end
54
+
55
+ def send_confirmation_instructions_with_certification
56
+ send_confirmation_instructions_without_certification if certified?
57
+ end
58
+
59
+ def unless_certified
60
+ unless certified?
61
+ yield
62
+ else
63
+ self.errors.add(:email, :already_certified)
64
+ false
65
+ end
66
+ end
67
+
68
+ # Generate certification token
69
+ def generate_certification_token
70
+ self.certification_token = self.class.certification_token
71
+ self.certified_at = nil
72
+ self.certified_by = nil
73
+ end
74
+
75
+ def generate_certification_token!
76
+ generate_certification_token && save(:validate => false)
77
+ end
78
+
79
+ module ClassMethods
80
+ # Generate token
81
+ def certification_token
82
+ generate_token(:certification_token)
83
+ end
84
+
85
+ def certify_by_token(certification_token, certification_authority)
86
+ certifiable = find_resource_by_token(certification_token)
87
+ certifiable.certify!(certification_authority) if certifiable.persisted?
88
+ certifiable
89
+ end
90
+
91
+ def find_resource_by_token(certification_token)
92
+ certifiable = find_or_initialize_with_error_by(:certification_token, certification_token)
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ module DeviseCertifiable
2
+ class Engine < ::Rails::Engine
3
+
4
+ ActiveSupport.on_load(:action_controller) { include DeviseCertifiable::Controllers::UrlHelpers }
5
+ ActiveSupport.on_load(:action_view) { include DeviseCertifiable::Controllers::UrlHelpers }
6
+
7
+ config.to_prepare do
8
+ require 'devise/mailer'
9
+ Devise::Mailer.send :include, DeviseCertifiable::Mailer
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+
4
+ protected
5
+ def devise_certification(mapping, controllers)
6
+ resource :certification, :only => [:edit, :update],
7
+ :path => mapping.path_names[:certification], :controller => controllers[:certifications]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module DeviseCertifiable
2
+ module Schema
3
+ def certifiable
4
+ apply_devise_schema :certification_token, String, :limit => 60
5
+ apply_devise_schema :certified_at, DateTime
6
+ apply_devise_schema :certified_by_id, Integer
7
+ apply_devise_schema :certified_by_type, String
8
+ end
9
+ end
10
+ end
11
+
12
+ Devise::Schema.send :include, DeviseCertifiable::Schema
@@ -0,0 +1,3 @@
1
+ module DeviseCertifiable
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class DeviseCertifiableGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def copy_devise_migration
9
+ migration_template "migration.rb", "db/migrate/devise_certifiable_add_to_#{table_name}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ class DeviseCertifiableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table :<%= table_name %> do |t|
4
+ t.string :certification_token, :limit => 60
5
+ t.datetime :certified_at
6
+ t.references :certified_by, :polymorphic => true
7
+ t.index :certification_token
8
+ t.index :certified_by_id
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ change_table :<%= table_name %> do |t|
14
+ t.remove_references :certified_by, :polymorphic => true
15
+ t.remove :certification_token, :certified_at
16
+ end
17
+ end
18
+ end