token_master 0.0.1 → 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.
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