token_master 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5790941a8c9d0ec6eacb36b1df7c473acc880c51
4
- data.tar.gz: affb3fad61df083f6a9d723b638d55b3d8e8a27b
3
+ metadata.gz: dd04ff6bcd482acefe3cb6f02eef4cd186ef8722
4
+ data.tar.gz: 741a3a5d77632dd6736aaa7546d1aac10eafc69b
5
5
  SHA512:
6
- metadata.gz: 4c88cfdaffea449b8393a25ee549972d4a746328f9b0adf7e25ffe9aaf87be9583d3f7ff0859eba2d7fb272050852f21ff298118456d9b1494eaf83b2b1455dc
7
- data.tar.gz: d87767fbaf677e52b5aea2904564e5c7888133e288e747e2071d2c4b4248fc9102a85950a508ffe56b681600759d66a880b06230a7ce2b0e8c6c7d3173871afb
6
+ metadata.gz: 4f5937cb91561db88615e0dcb47e772fa0f9751ba70914cf2e7fcd7dc5e5b10a3226a95241c1fd666f9de0597ec860244c7d069914e09236d95260de28283ff2
7
+ data.tar.gz: 53ae9e0eb252be8acf703999eccba66fa40ac3d647137fa4e21db444b14e9b13fa3bad293dd89fdd76dd16e4c5b9fad1cc1a0173702658ef52a21813462fa5cb
data/.gitignore CHANGED
@@ -1,3 +1,7 @@
1
1
  .DS_Store
2
- .yardoc
2
+ token_master-*.gem
3
+ Gemfile.lock
4
+ coverage
5
+ .yardopts
3
6
  doc
7
+ .yardoc
data/.travis.yml CHANGED
@@ -1 +1,8 @@
1
1
  language: ruby
2
+
3
+ addons:
4
+ code_climate:
5
+ repo_token: 455155dab5ce38bdda48bd7f4a94dd1e460889794046165191e5cf0a680e1999
6
+
7
+ after_success:
8
+ - bundle exec codeclimate-test-reporter
data/Gemfile CHANGED
@@ -1,3 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ group :test do
4
+ gem 'simplecov'
5
+ gem 'codeclimate-test-reporter', '~> 1.0.0'
6
+ end
7
+
3
8
  gemspec
data/README.md CHANGED
@@ -1,4 +1,10 @@
1
+ [![GitHub](http://img.shields.io/badge/github-launchpadlab/token_master-blue.svg)](http://github.com/launchpadlab/token_master)
2
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/token_master)
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/token_master.svg)](https://badge.fury.io/rb/token_master)
1
5
  [![Build Status](https://travis-ci.org/LaunchPadLab/token-master.svg?branch=master)](https://travis-ci.org/LaunchPadLab/token-master)
6
+ [![Test Coverage](https://codeclimate.com/github/LaunchPadLab/token-master/badges/coverage.svg)](https://codeclimate.com/github/LaunchPadLab/token-master/coverage)
7
+ [![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
2
8
 
3
9
  # token-master
4
10
  User management logic using tokens
@@ -68,3 +74,6 @@ config.add_tokenable_options :confirm, TokenMaster::Config::DEFAULT_VALUES
68
74
 
69
75
  config.add_tokenable_options :reset, token_lifetime: 1, required_params: [:password, :password_confirmation], token_length: 15
70
76
  ```
77
+
78
+ ## Api Documentation
79
+ [Rdoc](http://www.rubydoc.info/gems/token_master)
data/Rakefile CHANGED
@@ -1,13 +1,8 @@
1
1
  require 'rake/testtask'
2
- require 'yard'
3
2
 
4
3
  Rake::TestTask.new do |t|
5
4
  t.libs << 'test'
6
5
  end
7
6
 
8
- YARD::Rake::YardocTask.new do |t|
9
- t.files = ['lib/**/*.rb']
10
- end
11
-
12
7
  desc 'Run tests'
13
8
  task default: :test
data/lib/token_master.rb CHANGED
@@ -14,4 +14,4 @@ require 'token_master/core'
14
14
  require 'token_master/error'
15
15
  require 'token_master/model'
16
16
  require 'token_master/version'
17
- require 'token_master/railtie' if defined?(::Rails)
17
+ require 'token_master/railtie' if defined?(::Rails)
@@ -1,5 +1,11 @@
1
1
  module TokenMaster
2
+ # `TokenMaster::Config` manages the configuration options for tokenable actions. These can be set with the initializer provided with the generator. Default values will be used if options are not specified
2
3
  class Config
4
+
5
+ # Provides default values for a tokenable action:
6
+ # * `token_lifetime` is an integer representing the number of days before the token expires
7
+ # * `required_params` is an array of symbols, e.g., `[:password, :password_confirmation]`
8
+ # * `token_length` is an integer representing the number of characters in the token
3
9
  DEFAULT_VALUES = {
4
10
  token_lifetime: 14,
5
11
  required_params: [],
@@ -8,26 +14,50 @@ module TokenMaster
8
14
 
9
15
  attr_accessor :options
10
16
 
17
+ # Creates a new instance of `TokenMaster::Config`
11
18
  def initialize
12
19
  @options = {}
13
20
  end
14
21
 
22
+ # Sets the key-value pairs needed to complete a tokenable action<br /> Key-value pairs used to complete a tokenable action are the `token_lifetime`, `required_params` (can be blank), and `token_length`
23
+ # @example Set a Tokenable Option
24
+ # config.add_tokenable_options(:invite, { token_lifetime: 10, required_params: [:password, :password_confirmation], token_length: 12 }) #=>
25
+ # { invite: {
26
+ # token_lifetime: 10,
27
+ # required_params: [:password, :password_confirmation],
28
+ # token_length: 12
29
+ # }
30
+ # }
31
+ # @param [Symbol] key the tokenable action
32
+ # @param [Symbol=>[Integer, String, Array]] params the key-value pairs
15
33
  def add_tokenable_options(key, **params)
16
34
  @options[key] = params
17
35
  end
18
36
 
37
+ # Retrieves the `required_params` for a tokenable_action, either as set by the application, or by the default<br /> Used to update model attributes as needed for a given tokenable action
38
+ # @param [Symbol] key the tokenable action
39
+ # @return [Array] the `required_params` for a tokenable action
19
40
  def get_required_params(key)
20
41
  get_option(key, :required_params)
21
42
  end
22
43
 
44
+ # Retrieves the `token_lifetime` for a tokenable action, either as set by the application, or by the default
45
+ # @param [Symbol] key the tokenable action
46
+ # @return [Integer] the `token_lifetime` for a tokenable action
23
47
  def get_token_lifetime(key)
24
48
  get_option(key, :token_lifetime)
25
49
  end
26
50
 
51
+ # Retrieves the `token_length` for a tokenable action, either as set by the application, or by the default
52
+ # @param [Symbol] key the tokenable action
53
+ # @return [Integer] the `token_length` for a tokenable action
27
54
  def get_token_length(key)
28
55
  get_option(key, :token_length)
29
56
  end
30
57
 
58
+ # Determines whether options are provided for a tokenable action
59
+ # @param [Symbol] key the tokenable action
60
+ # @return [Boolean] `true` => options are set; `false` => options are not set
31
61
  def options_set?(key)
32
62
  @options.key? key
33
63
  end
@@ -2,10 +2,21 @@ require 'token_master/error'
2
2
  require 'securerandom'
3
3
 
4
4
  module TokenMaster
5
- # TODO
5
+ # `TokenMaster::Core` provides the core functionality of the TokenMaster gem. The `Core` module performs all of the logic of completing tokenable actions, and provides descriptive messages of the status or abilities of calls made.
6
6
  module Core
7
7
  class << self
8
- # TODO
8
+
9
+ # Completes the tokenable action for a tokenable model instance using a token, setting `tokenable_completed_at` to the time at completion
10
+ # @param [Object] klass the tokenable Class
11
+ # @param [String, Symbol] key the tokenable action
12
+ # @param token [String] the tokenable's token used to complete the action
13
+ # @param params [Symbol=>String] keyword arguments required to complete the tokenable action
14
+ # @raise [NotTokenableError] if the provided Class does not have the correct tokenable column
15
+ # @raise [TokenNotFoundError] if a tokenable instance cannot be found by the given token
16
+ # @raise [TokenCompletedError] if the tokenable action has already been completed, i.e., the tokenable instance has a timestamp in `tokenable_completed_at`
17
+ # @raise [TokenExpiredError] if the token is expired, i.e., the date is beyond the token's `created_at` plus `token_lifetime`
18
+ # @raise [MissingRequiredParamsError] if the params required by a tokenable are not provided
19
+ # @return [Object] tokenable Class instance
9
20
  def do_by_token!(klass, key, token, **params)
10
21
  check_manageable! klass, key
11
22
  token_column = { token_col(key) => token }
@@ -19,7 +30,16 @@ module TokenMaster
19
30
  model
20
31
  end
21
32
 
22
- # TODO
33
+ # Completes the token action for a tokenable instance _without_ a token, setting the `tokenable_completed_at` to the time at completion.<br /> Usually implemented when you want to complete multiple tokenable actions at once, e.g., a user completes the invite action by setting up passwords, by default also completes the confirm action
34
+ # @example Force a Tokenable Action (Confirm)
35
+ # user.force_confirm! =>
36
+ # <User id: 205, name: "John Smith", email: "jsmith@example.com", confirm_token: nil, confirm_created_at: nil, confirm_sent_at: nil, confirm_completed_at: "2017-04-25 14:17:13">
37
+ # @param [Object] model the tokenable model instance
38
+ # @param [String, Symbol] key the tokenable action
39
+ # @param [Symbol=>String] params keyword arguments required to complete the tokenable action
40
+ # @raise [NotTokenableError] if the provided Class does not have the correct tokenable column
41
+ # @raise [MissingRequiredParamsError] if the params required by a tokenable are not provided
42
+ # @return [Object] tokenable Class instance
23
43
  def force_tokenable!(model, key, **params)
24
44
  check_manageable! model.class, key
25
45
  check_params! key, params
@@ -30,10 +50,14 @@ module TokenMaster
30
50
  model
31
51
  end
32
52
 
33
- # TODO
53
+ # Generates a tokenable action token, sets the token and the time of creation on the tokenable model instance
54
+ # @param [Object] model the tokenable model instance
55
+ # @param [String, Symbol] key the tokenable action
56
+ # @param [Integer] token_length the length of the generated token, method will use configuration token_length if not provided otherwise
57
+ # @raise [NotTokenableError] if the provided Class does not have the correct tokenable column
58
+ # @return [String] token
34
59
  def set_token!(model, key, token_length = nil)
35
60
  check_manageable! model.class, key
36
- check_configs_set! key
37
61
  token_length ||= TokenMaster.config.get_token_length(key.to_sym)
38
62
  token = generate_token token_length
39
63
 
@@ -47,7 +71,16 @@ module TokenMaster
47
71
  token
48
72
  end
49
73
 
50
- # TODO
74
+ # Accepts a block to pass on a generated token through a block, such as a mailer method, and sets `tokenable_sent_at` to the time the method is called
75
+ # @example Send Reset Instructions
76
+ # user.send_reset_instruction! { user.send_email } =>
77
+ # <User id: 205, name: "John Smith", email: "jsmith@example.com", reset_token: "3YcHkTJ7kXwV5wM", reset_created_at: 2017-04-25 14:20:54", reset_sent_at: "2017-04-25 14:22:42", reset_completed_at: nil>
78
+ # @param [Object] model the tokenable model instance
79
+ # @param [String, Symbol] key the tokenable action
80
+ # @raise [NotTokenableError] if the provided Class does not have the correct tokenable column
81
+ # @raise [TokenNotSetError] if the tokenable model instance does not have a token for the tokenable action
82
+ # @raise [TokenSentError] if this has already been called for the instance and tokenable action, i.e., `tokenable_sent_at` is not `nil`
83
+ # @return [Object] tokenable model instance
51
84
  def send_instructions!(model, key)
52
85
  check_manageable! model.class, key
53
86
  check_token_set! model, key
@@ -59,7 +92,16 @@ module TokenMaster
59
92
  model.save(validate: false)
60
93
  end
61
94
 
62
- # TODO
95
+ # Provides the status of the tokenable action, whether the action has been completed, the token has been sent, the token is expired, or the token has only been created
96
+ # @param [Object] model the tokenable model instance
97
+ # @param [String, Symbol] key the tokenable action
98
+ # @raise [NotTokenableError] if the provided Class does not have the correct tokenable column
99
+ # @return [String] status of the tokenable action:
100
+ # * completed
101
+ # * sent
102
+ # * expired
103
+ # * created
104
+ # * no token
63
105
  def status(model, key)
64
106
  check_manageable! model.class, key
65
107
  return 'completed' if completed?(model, key)
@@ -93,12 +135,8 @@ module TokenMaster
93
135
  TokenMaster.config.get_token_lifetime(key.to_sym)
94
136
  end
95
137
 
96
- def required_params(key)
97
- TokenMaster.config.required_params(key.to_sym)
98
- end
99
-
100
138
  def check_manageable!(klass, key)
101
- raise NotTokenable, "#{klass} not #{key}able" unless manageable?(klass, key)
139
+ raise Errors::NotTokenable, "#{klass} not #{key}able" unless manageable?(klass, key)
102
140
  end
103
141
 
104
142
  def manageable?(klass, key)
@@ -112,21 +150,17 @@ module TokenMaster
112
150
  ).all? { |attr| column_names.include? attr }
113
151
  end
114
152
 
115
- def check_configs_set!(key)
116
- raise NotConfigured, 'You have not set the configurations for this tokenable.' unless TokenMaster.config.options_set?(key.to_sym)
117
- end
118
-
119
153
  def check_params!(key, params)
120
154
  required_params = TokenMaster.config.get_required_params(key.to_sym)
121
- raise MissingRequiredParams, 'You did not pass in the required params for this tokenable' unless required_params.all? do |k|
155
+ raise Errors::MissingRequiredParams, 'You did not pass in the required params for this tokenable' unless required_params.all? do |k|
122
156
  params.keys.include? k
123
157
  end
124
158
  end
125
159
 
126
160
  def check_token_active!(model, key)
127
- raise TokenNotFound, "#{key} token not found" unless model
128
- raise TokenCompleted, "#{key} already completed" if completed?(model, key)
129
- raise TokenExpired, "#{key} token expired" unless token_active?(model, key)
161
+ raise Errors::TokenNotFound, "#{key} token not found" unless model
162
+ raise Errors::TokenCompleted, "#{key} already completed" if completed?(model, key)
163
+ raise Errors::TokenExpired, "#{key} token expired" unless token_active?(model, key)
130
164
  end
131
165
 
132
166
  def token_active?(model, key)
@@ -136,7 +170,7 @@ module TokenMaster
136
170
  end
137
171
 
138
172
  def check_instructions_sent!(model, key)
139
- raise TokenSent, "#{key} already sent" if instructions_sent?(model, key)
173
+ raise Errors::TokenSent, "#{key} already sent" if instructions_sent?(model, key)
140
174
  end
141
175
 
142
176
  def instructions_sent?(model, key)
@@ -148,17 +182,13 @@ module TokenMaster
148
182
  end
149
183
 
150
184
  def check_token_set!(model, key)
151
- raise TokenNotSet, "#{key}_token not set" unless token_set?(model, key)
185
+ raise Errors::TokenNotSet, "#{key}_token not set" unless token_set?(model, key)
152
186
  end
153
187
 
154
188
  def completed?(model, key)
155
189
  model.send(completed_at_col(key)).present?
156
190
  end
157
191
 
158
- def check_completed!(model, key)
159
- raise TokenNotCompleted, "#{key} not completed" unless completed?(model, key)
160
- end
161
-
162
192
  def generate_token(length)
163
193
  rlength = (length * 3) / 4
164
194
  SecureRandom.urlsafe_base64(rlength).tr('lIO0', 'sxyz')
@@ -1,36 +1,32 @@
1
1
  module TokenMaster
2
+ # `TokenMaster::Errors` holds all of the error classes used in applying TokenMaster
3
+ module Errors
4
+ # The base class for all errors raised by TokenMaster
5
+ class Error < StandardError; end
2
6
 
3
- # The base class for all errors raised by TokenMaster
4
- class Error < StandardError; end
7
+ # Raised when the attributes for a tokenable do not exist.
8
+ # This could result from a migration not being run or a spelling error
9
+ class NotTokenable < Error; end
5
10
 
6
- # TODO
7
- class MissingRequiredParams < Error; end
11
+ # Raised when the required parameters for a tokenable are not provided.
12
+ # This typically happens with reset and invite tokenables, that might require both `password` and `password_confirmation` fields,
13
+ # but only one is provided to the method
14
+ class MissingRequiredParams < Error; end
8
15
 
9
- # Raised when the attributes for a tokenable do not exist.
10
- # This could result from a migration not being run or a spelling error
11
- class NotTokenable < Error; end
16
+ # Raised when the tokenable instance is not found
17
+ class TokenNotFound < Error; end
12
18
 
13
- # TODO
14
- class NotConfigured < Error; end
19
+ # Raised when the status of the token is reviewed, but the tokenable action has already been completed
20
+ class TokenCompleted < Error; end
15
21
 
16
- # TODO
17
- class MissingRequiredParams < Error; end
22
+ # Raised when the token has expired based on the tokenable's `token_lifetime`
23
+ class TokenExpired < Error; end
18
24
 
19
- # TODO
20
- class TokenNotFound < Error; end
25
+ # Raised when the tokenable instructions have already been sent when calling `send_tokenable_instructions!`
26
+ class TokenSent < Error; end
21
27
 
22
- # TODO
23
- class TokenCompleted < Error; end
24
-
25
- # TODO
26
- class TokenNotCompleted < Error; end
27
-
28
- # TODO
29
- class TokenExpired < Error; end
30
-
31
- # TODO
32
- class TokenSent < Error; end
33
-
34
- # TODO
35
- class TokenNotSet < Error; end
28
+ # Raised when the tokenable model instance does not have a token set for a tokenable action
29
+ class TokenNotSet < Error; end
30
+ end
36
31
  end
32
+
@@ -1,34 +1,41 @@
1
1
  module TokenMaster
2
2
 
3
- # TODO
3
+ # `TokenMaster::Model` provides the interface to the app it is used in, providing access to its public methods by invoking `TokenMaster::ClassMethods` and definiing the appropriate methods on the app model(s).
4
4
  module Model
5
+ # Includes `TokenMaster::Model` and extends `TokenMaster::ClassMethods` to the class it's used with (automatically included via Railties)
5
6
  def self.included(base)
6
7
  base.extend(ClassMethods)
7
8
  end
8
9
 
10
+ # `TokenMaster::ClassMethods` defines methods on the tokenable Class to be used in applying TokenMaster
9
11
  module ClassMethods
10
- # TODO
12
+ # Iterates over each of the tokenables provided in the generator arguments to define the appropriate TokenMaster methods on the tokenable model
11
13
  def token_master(*tokenables)
12
14
  tokenables.each do |tokenable|
13
15
  # instance methods
14
- # TODO
16
+
17
+ # Defines a method on the tokenable model instance to generate a tokenable action token, e.g., `user.set_confim_token!`
15
18
  define_method("set_#{tokenable}_token!") do
16
19
  TokenMaster::Core.set_token!(self, tokenable)
17
20
  end
18
- # TODO
19
- define_method("send_#{tokenable}_instructions!") do |email|
20
- TokenMaster::Core.send_instructions!(self, tokenable, email)
21
+
22
+ # Defines a method on the tokenable model instance to send tokenable action instructions, e.g., `user.send_confim_instructions!`. Accepts a block with app logic to send instructions.
23
+ define_method("send_#{tokenable}_instructions!") do |&email|
24
+ TokenMaster::Core.send_instructions!(self, tokenable, &email)
21
25
  end
22
- # TODO
26
+
27
+ # Defines a method on the tokenable model instance to retrieve the status of a tokenable action, e.g., `user.confim_status`
23
28
  define_method("#{tokenable}_status") do
24
29
  TokenMaster::Core.status(self, tokenable)
25
30
  end
26
- # TODO
31
+
32
+ # Defines a method on the tokenable model instance to force the completion of a tokenable action, e.g., `user.force_confim!`. Accepts keyword arguments for `required_params`.
27
33
  define_method("force_#{tokenable}!") do |**params|
28
34
  TokenMaster::Core.force_tokenable!(self, tokenable, **params)
29
35
  end
30
36
  # class methods
31
- # TODO
37
+
38
+ # Defines a method on the tokenable model class to completed a tokenable action given a token, e.g., `User.confim_by_token!`. Takes the token and accepts any keyword arguments for `required_params`.
32
39
  define_singleton_method("#{tokenable}_by_token!") do |token, **params|
33
40
  TokenMaster::Core.do_by_token!(self, tokenable, token, **params)
34
41
  end
@@ -1,3 +1,4 @@
1
1
  module TokenMaster
2
- VERSION = '0.0.1'.freeze
2
+ # Current version of TokenMaster
3
+ VERSION = '0.1.0'.freeze
3
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: token_master
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Corwin
@@ -61,7 +61,6 @@ files:
61
61
  - ".ruby-version"
62
62
  - ".travis.yml"
63
63
  - Gemfile
64
- - Gemfile.lock
65
64
  - LICENSE.txt
66
65
  - README.md
67
66
  - Rakefile
@@ -98,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
97
  version: '0'
99
98
  requirements: []
100
99
  rubyforge_project:
101
- rubygems_version: 2.6.6
100
+ rubygems_version: 2.5.1
102
101
  signing_key:
103
102
  specification_version: 4
104
103
  summary: Token Master!
data/Gemfile.lock DELETED
@@ -1,23 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- token_master (0.0.1)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- minitest (5.10.1)
10
- rake (10.4.2)
11
- yard (0.9.8)
12
-
13
- PLATFORMS
14
- ruby
15
-
16
- DEPENDENCIES
17
- minitest (~> 5.10.1)
18
- rake (~> 10.4.2)
19
- token_master!
20
- yard
21
-
22
- BUNDLED WITH
23
- 1.14.5