token_action 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +143 -0
  3. data/Rakefile +16 -0
  4. data/app/controllers/token_action/application_controller.rb +4 -0
  5. data/app/controllers/token_action/tokens_controller.rb +73 -0
  6. data/config/locales/en.yml +10 -0
  7. data/config/routes.rb +3 -0
  8. data/lib/generators/active_record/templates/migration.rb +15 -0
  9. data/lib/generators/active_record/token_action_generator.rb +25 -0
  10. data/lib/generators/mongoid/token_action_generator.rb +7 -0
  11. data/lib/generators/templates/README +10 -0
  12. data/lib/generators/templates/token_action.rb +25 -0
  13. data/lib/generators/token_action_generator.rb +35 -0
  14. data/lib/token_action/engine.rb +5 -0
  15. data/lib/token_action/mixins/model.rb +24 -0
  16. data/lib/token_action/mixins/token_generator.rb +19 -0
  17. data/lib/token_action/orm/active_record.rb +10 -0
  18. data/lib/token_action/orm/mongoid.rb +34 -0
  19. data/lib/token_action/version.rb +3 -0
  20. data/lib/token_action.rb +71 -0
  21. data/spec/controllers/token_action/tokens_controller_spec.rb +172 -0
  22. data/spec/dummy/Rakefile +7 -0
  23. data/spec/dummy/app/active_record/cat.rb +18 -0
  24. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  25. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  26. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  27. data/spec/dummy/app/controllers/hello_controller.rb +25 -0
  28. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  29. data/spec/dummy/app/mongoid/cat.rb +22 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/spec/dummy/config/application.rb +71 -0
  32. data/spec/dummy/config/boot.rb +15 -0
  33. data/spec/dummy/config/database.yml +18 -0
  34. data/spec/dummy/config/environment.rb +5 -0
  35. data/spec/dummy/config/environments/development.rb +37 -0
  36. data/spec/dummy/config/environments/production.rb +67 -0
  37. data/spec/dummy/config/environments/test.rb +41 -0
  38. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  39. data/spec/dummy/config/initializers/session_store.rb +8 -0
  40. data/spec/dummy/config/initializers/token_action.rb +5 -0
  41. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  42. data/spec/dummy/config/locales/en.yml +5 -0
  43. data/spec/dummy/config/locales/token_action.en.yml +26 -0
  44. data/spec/dummy/config/mongoid.yml +68 -0
  45. data/spec/dummy/config/routes.rb +9 -0
  46. data/spec/dummy/config.ru +4 -0
  47. data/spec/dummy/db/development.sqlite3 +0 -0
  48. data/spec/dummy/db/migrate/20130104151630_create_token_action_tokens.rb +15 -0
  49. data/spec/dummy/db/migrate/20130104201018_create_cats.rb +7 -0
  50. data/spec/dummy/log/development.log +16 -0
  51. data/spec/dummy/log/test.log +4739 -0
  52. data/spec/dummy/public/404.html +26 -0
  53. data/spec/dummy/public/422.html +26 -0
  54. data/spec/dummy/public/500.html +25 -0
  55. data/spec/dummy/public/favicon.ico +0 -0
  56. data/spec/dummy/script/rails +6 -0
  57. data/spec/factories.rb +6 -0
  58. data/spec/routing/token_action/tokens_routing_spec.rb +33 -0
  59. data/spec/spec_helper.rb +94 -0
  60. data/spec/token_action/mixins/model_spec.rb +13 -0
  61. data/spec/token_action/mixins/token_generator_spec.rb +11 -0
  62. data/spec/token_action/orm/active_record_spec.rb +6 -0
  63. data/spec/token_action/orm/mongoid_spec.rb +6 -0
  64. data/spec/token_action_spec.rb +67 -0
  65. metadata +394 -0
@@ -0,0 +1,10 @@
1
+ require 'orm_adapter/adapters/active_record'
2
+
3
+ module TokenAction
4
+ # A token to authenticate an action.
5
+ class Token < ActiveRecord::Base
6
+ include TokenAction::Model
7
+
8
+ serialize :args
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ require 'orm_adapter/adapters/mongoid'
2
+
3
+ module TokenAction
4
+ # A token to authenticate an action.
5
+ class Token
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ include TokenAction::Model
10
+
11
+ # A shared secret.
12
+ # @return [String] a token
13
+ field :token, :type => String
14
+
15
+ # The class on which to perform the action.
16
+ # @return [String] a class name
17
+ # @note `class` clashes with `Object#class` and Mongoid reserves `klass`.
18
+ field :kind, :type => String
19
+
20
+ # Any additional arguments for the action.
21
+ # @return [Array] a list of arguments
22
+ field :args, :type => Array
23
+
24
+ # The URL to redirect to after performing the action successfully.
25
+ # @return [String] a URL or path
26
+ field :success_url, :type => String
27
+
28
+ # The URL to redirect to after failing to perform the action.
29
+ # @return [String] a URL or path
30
+ field :failure_url, :type => String
31
+
32
+ index({:token => 1}, :unique => true)
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module TokenAction
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,71 @@
1
+ require 'token_action/engine'
2
+
3
+ require 'securerandom'
4
+
5
+ require 'active_support/concern'
6
+ require 'orm_adapter'
7
+
8
+ module TokenAction
9
+ # Returns the default success URL.
10
+ #
11
+ # @return [String] the default success URL
12
+ def self.success_url
13
+ if Proc === @@success_url
14
+ @@success_url.call
15
+ else
16
+ @@success_url
17
+ end
18
+ end
19
+
20
+ # Sets the default success URL.
21
+ #
22
+ # @param [String,Proc] a default success URL
23
+ def self.success_url=(success_url)
24
+ @@success_url = success_url
25
+ end
26
+
27
+ # Returns the default failure URL.
28
+ #
29
+ # @return [String] the default failure URL
30
+ def self.failure_url
31
+ if Proc === @@failure_url
32
+ @@failure_url.call
33
+ else
34
+ @@failure_url
35
+ end
36
+ end
37
+
38
+ # Sets the default failure URL.
39
+ #
40
+ # @param [String,Proc] a default failure URL
41
+ def self.failure_url=(failure_url)
42
+ @@failure_url = failure_url
43
+ end
44
+
45
+ # Configures TokenAction.
46
+ #
47
+ # * `success_url`: the default success URL
48
+ # * `failure_url`: the default failure URL
49
+ #
50
+ # @example
51
+ # require 'token_action'
52
+ #
53
+ # TokenAction.setup do |config|
54
+ # config.success_url = '/home'
55
+ # config.failure_url = '/oops'
56
+ # end
57
+ def self.setup
58
+ yield self
59
+ end
60
+
61
+ # Returns a random alphanumeric string.
62
+ #
63
+ # @return [String] a random alphanumeric string
64
+ # @see Devise::friendly_token
65
+ def self.friendly_token
66
+ SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
67
+ end
68
+ end
69
+
70
+ require 'token_action/mixins/token_generator'
71
+ require 'token_action/mixins/model'
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+
3
+ describe TokenAction::TokensController do
4
+ before :each do
5
+ @routes = TokenAction::Engine.routes
6
+ end
7
+
8
+ describe 'GET redeem' do
9
+ context 'after failing to perform the action' do
10
+ let :token_with_failure_url do
11
+ FactoryGirl.create(:token, :args => ['upgrade'], :failure_url => '/hello/token_failure').token
12
+ end
13
+ let :token_with_unroutable_failure_url do
14
+ FactoryGirl.create(:token, :args => ['upgrade'], :failure_url => '/missing').token
15
+ end
16
+ let :token_without_failure_url do
17
+ FactoryGirl.create(:token, :args => ['upgrade']).token
18
+ end
19
+ let :token_with_error do
20
+ FactoryGirl.create(:token, :args => ['metamorphose']).token
21
+ end
22
+ let :token_with_namespaced_error do
23
+ FactoryGirl.create(:token, :args => ['fly']).token
24
+ end
25
+
26
+ it "redirects to the token's failure URL" do
27
+ TokenAction.failure_url = '/hello/failure'
28
+ get :redeem, :token => token_with_failure_url, :path => 'redeem'
29
+ response.should redirect_to '/hello/token_failure'
30
+ end
31
+ it "redirects to the default failure URL if the token's failure URL is not routable" do
32
+ TokenAction.failure_url = '/hello/failure'
33
+ get :redeem, :token => token_with_unroutable_failure_url, :path => 'redeem'
34
+ response.should redirect_to '/hello/failure'
35
+ end
36
+ it "redirects to the default failure URL if the token's failure URL is not set" do
37
+ TokenAction.failure_url = '/hello/failure'
38
+ get :redeem, :token => token_without_failure_url, :path => 'redeem'
39
+ response.should redirect_to '/hello/failure'
40
+ end
41
+ it "redirects to the application's root_path if the default failure URL is not routable" do
42
+ TokenAction.failure_url = '/missing'
43
+ get :redeem, :token => token_without_failure_url, :path => 'redeem'
44
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
45
+ end
46
+ it "redirects to the application's root_path if the default failure URL is not set" do
47
+ TokenAction.failure_url = nil
48
+ get :redeem, :token => token_without_failure_url, :path => 'redeem'
49
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
50
+ end
51
+
52
+ it 'flashes a path-based, error-based failure message' do
53
+ get :redeem, :token => token_with_error, :path => 'confirm'
54
+ flash[:notice].should be_nil
55
+ flash[:alert].should == 'This is an path-based, error-based failure message.'
56
+ end
57
+ it 'flashes a error-based failure message' do
58
+ get :redeem, :token => token_with_error, :path => 'redeem'
59
+ flash[:notice].should be_nil
60
+ flash[:alert].should == 'This is an error-based failure message.'
61
+ end
62
+ it 'flashes a long error-based failure message' do
63
+ get :redeem, :token => token_with_namespaced_error, :path => 'redeem'
64
+ flash[:notice].should be_nil
65
+ flash[:alert].should == 'This is another error-based failure message.'
66
+ end
67
+ it 'flashes a path-based failure message' do
68
+ get :redeem, :token => token_without_failure_url, :path => 'confirm'
69
+ flash[:notice].should be_nil
70
+ flash[:alert].should == 'This is a path-based failure message.'
71
+ end
72
+ it 'flashes a long path-based failure message' do
73
+ get :redeem, :token => token_without_failure_url, :path => 'a/b/c'
74
+ flash[:notice].should be_nil
75
+ flash[:alert].should == 'This is another path-based failure message.'
76
+ end
77
+ it 'flashes the default failure message' do
78
+ get :redeem, :token => token_without_failure_url, :path => 'redeem'
79
+ flash[:notice].should be_nil
80
+ flash[:alert].should == 'An error occurred while processing your request.'
81
+ end
82
+ end
83
+
84
+ context 'when the token is not found' do
85
+ it 'redirects to the default failure URL' do
86
+ TokenAction.failure_url = '/hello/not_found'
87
+ get :redeem, :token => 'missing', :path => 'redeem'
88
+ response.should redirect_to '/hello/not_found'
89
+ end
90
+ it "redirects to the application's root_path if the default failure URL is not routable" do
91
+ TokenAction.failure_url = '/missing'
92
+ get :redeem, :token => 'missing', :path => 'redeem'
93
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
94
+ end
95
+ it "redirects to the application's root_path if the default failure URL is not set" do
96
+ TokenAction.failure_url = nil
97
+ get :redeem, :token => 'missing', :path => 'redeem'
98
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
99
+ end
100
+
101
+ it 'flashes a path-based failure message' do
102
+ get :redeem, :token => 'missing', :path => 'confirm'
103
+ flash[:notice].should be_nil
104
+ flash[:alert].should == 'This is a path-based not found message.'
105
+ end
106
+ it 'flashes a long path-based failure message' do
107
+ get :redeem, :token => 'missing', :path => 'a/b/c'
108
+ flash[:notice].should be_nil
109
+ flash[:alert].should == 'This is another path-based not found message.'
110
+ end
111
+ it 'flashes the default failure message if no path-based failure message is set' do
112
+ get :redeem, :token => 'missing', :path => 'redeem'
113
+ flash[:notice].should be_nil
114
+ flash[:alert].should == 'Sorry, your request could not be processed.'
115
+ end
116
+ end
117
+
118
+ context 'after performing the action successfully' do
119
+ let :token_with_success_url do
120
+ FactoryGirl.create(:token, :success_url => '/hello/token_success').token
121
+ end
122
+ let :token_with_unroutable_success_url do
123
+ FactoryGirl.create(:token, :success_url => '/missing').token
124
+ end
125
+ let :token_without_success_url do
126
+ FactoryGirl.create(:token).token
127
+ end
128
+
129
+ it "redirects to the token's success URL" do
130
+ TokenAction.success_url = '/hello/success'
131
+ get :redeem, :token => token_with_success_url, :path => 'redeem'
132
+ response.should redirect_to '/hello/token_success'
133
+ end
134
+ it "redirects to the default success URL if the token's success URL is not routable" do
135
+ TokenAction.success_url = '/hello/success'
136
+ get :redeem, :token => token_with_unroutable_success_url, :path => 'redeem'
137
+ response.should redirect_to '/hello/success'
138
+ end
139
+ it "redirects to the default success URL if the token's success URL is not set" do
140
+ TokenAction.success_url = '/hello/success'
141
+ get :redeem, :token => token_without_success_url, :path => 'redeem'
142
+ response.should redirect_to '/hello/success'
143
+ end
144
+ it "redirects to the application's root_path if the default success URL is not routable" do
145
+ TokenAction.success_url = '/missing'
146
+ get :redeem, :token => token_without_success_url, :path => 'redeem'
147
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
148
+ end
149
+ it "redirects to the application's root_path if the default success URL is not set" do
150
+ TokenAction.success_url = nil
151
+ get :redeem, :token => token_without_success_url, :path => 'redeem'
152
+ response.should redirect_to Rails.application.routes.url_for(:controller => 'hello', :action => 'hello')
153
+ end
154
+
155
+ it 'flashes a path-based success message' do
156
+ get :redeem, :token => token_without_success_url, :path => 'confirm'
157
+ flash[:notice].should == 'This is a path-based success message.'
158
+ flash[:alert].should be_nil
159
+ end
160
+ it 'flashes a long path-based success message' do
161
+ get :redeem, :token => token_without_success_url, :path => 'a/b/c'
162
+ flash[:notice].should == 'This is another path-based success message.'
163
+ flash[:alert].should be_nil
164
+ end
165
+ it 'flashes the default success message if no path-based success message is set' do
166
+ get :redeem, :token => token_without_success_url, :path => 'redeem'
167
+ flash[:notice].should == 'Your request was successfully processed.'
168
+ flash[:alert].should be_nil
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,18 @@
1
+ class AnimalError < StandardError; end
2
+ class MammalError < StandardError; end
3
+
4
+ class Cat < ActiveRecord::Base
5
+ class CatError < StandardError; end
6
+ include TokenAction::TokenGenerator
7
+
8
+ def self.redeem_token(action = nil)
9
+ case action
10
+ when 'upgrade'
11
+ raise AnimalError.new
12
+ when 'metamorphose'
13
+ raise MammalError.new
14
+ when 'fly'
15
+ raise CatError.new
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,25 @@
1
+ class HelloController < ApplicationController
2
+ def hello
3
+ render :text => 'Hello, world'
4
+ end
5
+
6
+ def token_success
7
+ render :nothing => true
8
+ end
9
+
10
+ def token_failure
11
+ render :nothing => true
12
+ end
13
+
14
+ def success
15
+ render :nothing => true
16
+ end
17
+
18
+ def failure
19
+ render :nothing => true
20
+ end
21
+
22
+ def not_found
23
+ render :nothing => true
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,22 @@
1
+ class AnimalError < StandardError; end
2
+ class MammalError < StandardError; end
3
+
4
+ class Cat
5
+ class CatError < StandardError; end
6
+ include TokenAction::TokenGenerator
7
+
8
+ include Mongoid::Document
9
+
10
+ field :token, :type => String
11
+
12
+ def self.redeem_token(action = nil)
13
+ case action
14
+ when 'upgrade'
15
+ raise AnimalError.new
16
+ when 'metamorphose'
17
+ raise MammalError.new
18
+ when 'fly'
19
+ raise CatError.new
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag "application", :media => "all" %>
6
+ <%= javascript_include_tag "application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,71 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require "action_controller/railtie"
4
+ require "action_mailer/railtie"
5
+ require "active_resource/railtie"
6
+ require "sprockets/railtie"
7
+
8
+ Bundler.require TOKEN_ACTION_ORM
9
+ require "token_action"
10
+
11
+ # @see https://github.com/plataformatec/devise/blob/master/test/rails_app/config/application.rb
12
+ begin
13
+ require "#{TOKEN_ACTION_ORM}/railtie" # e.g. "active_record/railtie"
14
+ rescue LoadError
15
+ # do nothing
16
+ end
17
+
18
+ module Dummy
19
+ class Application < Rails::Application
20
+ # @see https://github.com/plataformatec/devise/blob/master/test/rails_app/config/application.rb
21
+ config.autoload_paths += %W(#{config.root}/app/#{TOKEN_ACTION_ORM})
22
+
23
+ # Settings in config/environments/* take precedence over those specified here.
24
+ # Application configuration should go into files in config/initializers
25
+ # -- all .rb files in that directory are automatically loaded.
26
+
27
+ # Custom directories with classes and modules you want to be autoloadable.
28
+ # config.autoload_paths += %W(#{config.root}/extras)
29
+
30
+ # Only load the plugins named here, in the order given (default is alphabetical).
31
+ # :all can be used as a placeholder for all plugins not explicitly named.
32
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
33
+
34
+ # Activate observers that should always be running.
35
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
36
+
37
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
38
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
39
+ # config.time_zone = 'Central Time (US & Canada)'
40
+
41
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
42
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
43
+ # config.i18n.default_locale = :de
44
+
45
+ # Configure the default encoding used in templates for Ruby 1.9.
46
+ config.encoding = "utf-8"
47
+
48
+ # Configure sensitive parameters which will be filtered from the log file.
49
+ config.filter_parameters += [:password]
50
+
51
+ # Enable escaping HTML in JSON.
52
+ config.active_support.escape_html_entities_in_json = true
53
+
54
+ # Use SQL instead of Active Record's schema dumper when creating the database.
55
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
56
+ # like if you have constraints or database-specific column types
57
+ # config.active_record.schema_format = :sql
58
+
59
+ # Enforce whitelist mode for mass assignment.
60
+ # This will create an empty whitelist of attributes available for mass-assignment for all models
61
+ # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
62
+ # parameters by using an attr_accessible or attr_protected declaration.
63
+ # config.active_record.whitelist_attributes = true
64
+
65
+ # Enable the asset pipeline
66
+ config.assets.enabled = true
67
+
68
+ # Version of your assets, change this if you want to expire all your assets
69
+ config.assets.version = '1.0'
70
+ end
71
+ end