devise-tokens 1.0.0 → 1.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/devise_tokens/application_controller.rb +77 -0
  3. data/app/controllers/devise_tokens/concerns/resource_finder.rb +42 -0
  4. data/app/controllers/devise_tokens/concerns/set_user_by_token.rb +160 -0
  5. data/app/controllers/devise_tokens/confirmations_controller.rb +79 -0
  6. data/app/controllers/devise_tokens/omniauth_callbacks_controller.rb +284 -0
  7. data/app/controllers/devise_tokens/passwords_controller.rb +204 -0
  8. data/app/controllers/devise_tokens/registrations_controller.rb +203 -0
  9. data/app/controllers/devise_tokens/sessions_controller.rb +128 -0
  10. data/app/controllers/devise_tokens/token_validations_controller.rb +29 -0
  11. data/app/controllers/devise_tokens/unlocks_controller.rb +87 -0
  12. data/app/models/devise_token_auth/concerns/active_record_support.rb +16 -0
  13. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  14. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +19 -0
  15. data/app/models/devise_token_auth/concerns/user.rb +253 -0
  16. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +28 -0
  17. data/app/validators/devise_token_auth_email_validator.rb +23 -0
  18. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  19. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  20. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  21. data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
  22. data/config/locales/da-DK.yml +52 -0
  23. data/config/locales/de.yml +51 -0
  24. data/config/locales/en.yml +57 -0
  25. data/config/locales/es.yml +51 -0
  26. data/config/locales/fr.yml +51 -0
  27. data/config/locales/he.yml +52 -0
  28. data/config/locales/it.yml +48 -0
  29. data/config/locales/ja.yml +48 -0
  30. data/config/locales/nl.yml +32 -0
  31. data/config/locales/pl.yml +50 -0
  32. data/config/locales/pt-BR.yml +48 -0
  33. data/config/locales/pt.yml +50 -0
  34. data/config/locales/ro.yml +48 -0
  35. data/config/locales/ru.yml +52 -0
  36. data/config/locales/sq.yml +48 -0
  37. data/config/locales/sv.yml +52 -0
  38. data/config/locales/uk.yml +61 -0
  39. data/config/locales/vi.yml +52 -0
  40. data/config/locales/zh-CN.yml +48 -0
  41. data/config/locales/zh-HK.yml +50 -0
  42. data/config/locales/zh-TW.yml +50 -0
  43. data/lib/devise_tokens.rb +14 -0
  44. data/lib/devise_tokens/blacklist.rb +2 -0
  45. data/lib/devise_tokens/controllers/helpers.rb +161 -0
  46. data/lib/devise_tokens/controllers/url_helpers.rb +10 -0
  47. data/lib/devise_tokens/engine.rb +92 -0
  48. data/lib/devise_tokens/errors.rb +6 -0
  49. data/lib/devise_tokens/rails/routes.rb +116 -0
  50. data/lib/devise_tokens/token_factory.rb +126 -0
  51. data/lib/devise_tokens/url.rb +39 -0
  52. data/lib/devise_tokens/version.rb +3 -0
  53. data/lib/generators/devise_tokens/USAGE +31 -0
  54. data/lib/generators/devise_tokens/install_generator.rb +91 -0
  55. data/lib/generators/devise_tokens/install_generator_helpers.rb +98 -0
  56. data/lib/generators/devise_tokens/install_mongoid_generator.rb +46 -0
  57. data/lib/generators/devise_tokens/install_views_generator.rb +18 -0
  58. data/lib/generators/devise_tokens/templates/devise_tokens.rb +55 -0
  59. data/lib/generators/devise_tokens/templates/devise_tokens_create_users.rb.erb +49 -0
  60. data/lib/generators/devise_tokens/templates/user.rb.erb +9 -0
  61. data/lib/generators/devise_tokens/templates/user_mongoid.rb.erb +56 -0
  62. data/lib/tasks/devise_tokens_tasks.rake +6 -0
  63. metadata +208 -4
  64. data/lib/devise-tokens.rb +0 -5
@@ -0,0 +1,6 @@
1
+ module DeviseTokens
2
+ module Errors
3
+ class NoResourceDefinedError < StandardError; end
4
+ class InvalidModel < StandardError; end
5
+ end
6
+ end
@@ -0,0 +1,116 @@
1
+
2
+
3
+ module ActionDispatch::Routing
4
+ class Mapper
5
+ def mount_devise_tokens_for(resource, opts)
6
+ # ensure objects exist to simplify attr checks
7
+ opts[:controllers] ||= {}
8
+ opts[:skip] ||= []
9
+
10
+ # check for ctrl overrides, fall back to defaults
11
+ sessions_ctrl = opts[:controllers][:sessions] || 'devise_tokens/sessions'
12
+ registrations_ctrl = opts[:controllers][:registrations] || 'devise_tokens/registrations'
13
+ passwords_ctrl = opts[:controllers][:passwords] || 'devise_tokens/passwords'
14
+ confirmations_ctrl = opts[:controllers][:confirmations] || 'devise_tokens/confirmations'
15
+ token_validations_ctrl = opts[:controllers][:token_validations] || 'devise_tokens/token_validations'
16
+ omniauth_ctrl = opts[:controllers][:omniauth_callbacks] || 'devise_tokens/omniauth_callbacks'
17
+ unlocks_ctrl = opts[:controllers][:unlocks] || 'devise_tokens/unlocks'
18
+
19
+ # define devise controller mappings
20
+ controllers = { sessions: sessions_ctrl,
21
+ registrations: registrations_ctrl,
22
+ passwords: passwords_ctrl,
23
+ confirmations: confirmations_ctrl }
24
+
25
+ controllers[:unlocks] = unlocks_ctrl if unlocks_ctrl
26
+
27
+ # remove any unwanted devise modules
28
+ opts[:skip].each{ |item| controllers.delete(item) }
29
+
30
+ devise_for resource.pluralize.underscore.gsub('/', '_').to_sym,
31
+ class_name: resource,
32
+ module: :devise,
33
+ path: opts[:at].to_s,
34
+ controllers: controllers,
35
+ skip: opts[:skip] + [:omniauth_callbacks]
36
+
37
+ unnest_namespace do
38
+ # get full url path as if it were namespaced
39
+ full_path = "#{@scope[:path]}/#{opts[:at]}"
40
+
41
+ # get namespace name
42
+ namespace_name = @scope[:as]
43
+
44
+ # clear scope so controller routes aren't namespaced
45
+ @scope = ActionDispatch::Routing::Mapper::Scope.new(
46
+ path: '',
47
+ shallow_path: '',
48
+ constraints: {},
49
+ defaults: {},
50
+ options: {},
51
+ parent: nil
52
+ )
53
+
54
+ mapping_name = resource.underscore.gsub('/', '_')
55
+ mapping_name = "#{namespace_name}_#{mapping_name}" if namespace_name
56
+
57
+ devise_scope mapping_name.to_sym do
58
+ # path to verify token validity
59
+ get "#{full_path}/validate_token", controller: token_validations_ctrl.to_s, action: 'validate_token' if !opts[:skip].include?(:token_validations)
60
+
61
+ # omniauth routes. only define if omniauth is installed and not skipped.
62
+ if defined?(::OmniAuth) && !opts[:skip].include?(:omniauth_callbacks)
63
+ match "#{full_path}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get]
64
+ match "#{full_path}/:provider/callback", controller: omniauth_ctrl, action: 'omniauth_success', via: [:get]
65
+
66
+ match "#{DeviseTokens.omniauth_prefix}/:provider/callback", controller: omniauth_ctrl, action: 'redirect_callbacks', via: [:get, :post]
67
+ match "#{DeviseTokens.omniauth_prefix}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get, :post]
68
+
69
+ # preserve the resource class thru oauth authentication by setting name of
70
+ # resource as "resource_class" param
71
+ match "#{full_path}/:provider", to: redirect{ |params, request|
72
+ # get the current querystring
73
+ qs = CGI::parse(request.env['QUERY_STRING'])
74
+
75
+ # append name of current resource
76
+ qs['resource_class'] = [resource]
77
+ qs['namespace_name'] = [namespace_name] if namespace_name
78
+
79
+ set_omniauth_path_prefix!(DeviseTokens.omniauth_prefix)
80
+
81
+ redirect_params = {}.tap { |hash| qs.each{ |k, v| hash[k] = v.first } }
82
+
83
+ if DeviseTokens.redirect_whitelist
84
+ redirect_url = request.params['auth_origin_url']
85
+ unless DeviseTokens::Url.whitelisted?(redirect_url)
86
+ message = I18n.t(
87
+ 'devise_tokens.registrations.redirect_url_not_allowed',
88
+ redirect_url: redirect_url
89
+ )
90
+ redirect_params['message'] = message
91
+ next "#{::OmniAuth.config.path_prefix}/failure?#{redirect_params.to_param}"
92
+ end
93
+ end
94
+
95
+ # re-construct the path for omniauth
96
+ "#{::OmniAuth.config.path_prefix}/#{params[:provider]}?#{redirect_params.to_param}"
97
+ }, via: [:get]
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # this allows us to use namespaced paths without namespacing the routes
104
+ def unnest_namespace
105
+ current_scope = @scope.dup
106
+ yield
107
+ ensure
108
+ @scope = current_scope
109
+ end
110
+
111
+ # ignore error about omniauth/multiple model support
112
+ def set_omniauth_path_prefix!(path_prefix)
113
+ ::OmniAuth.config.path_prefix = path_prefix
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,126 @@
1
+ require 'bcrypt'
2
+
3
+ module DeviseTokens
4
+ # A token management factory which allow generate token objects and check them.
5
+ module TokenFactory
6
+ # For BCrypt::Password class see:
7
+ # https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb
8
+
9
+ # Creates a token instance. Takes an optional client, lifespan and cost options.
10
+ # Example:
11
+ # DeviseTokens::TokenFactory.create
12
+ # => #<struct DeviseTokens::TokenFactory::Token client="tElcgkdZ7f9XEa0unZhrYQ", token="rAMcWOs0-mGHFMnIgJD2cA", token_hash="$2a$10$wrsdlHVRGlYW11wfImxU..jr0Ux3bHo/qbXcSfgp8zmvVUNHosita", expiry=1518982690>
13
+ #
14
+ # DeviseTokens::TokenFactory.create(lifespan: 10, cost: 4)
15
+ # => #<struct DeviseTokens::TokenFactory::Token client="5qleT7_t9JPVcX9xmxkVYA", token="RBXX43u4xXNSO-fr2N_4pA", token_hash="$2a$04$9gpCaoFbu2dUKxU3qiTgluHX7jj9UzS.jq1QW0EkQmoaxARo1WxTy", expiry=1517773268>
16
+ def self.create(client: nil, lifespan: nil, cost: nil)
17
+ # obj_client = client.nil? ? client() : client
18
+ obj_client = client || client()
19
+ obj_token = token
20
+ obj_token_hash = token_hash(obj_token, cost)
21
+ obj_expiry = expiry(lifespan)
22
+
23
+ Token.new(obj_client, obj_token, obj_token_hash, obj_expiry)
24
+ end
25
+
26
+ # Generates a random URL-safe client.
27
+ # Example:
28
+ # DeviseTokens::TokenFactory.client
29
+ # => "zNf0pNP5iGfuBItZJGCseQ"
30
+ def self.client
31
+ secure_string
32
+ end
33
+
34
+ # Generates a random URL-safe token.
35
+ # Example:
36
+ # DeviseTokens::TokenFactory.token
37
+ # => "6Bqs4K9x8ChLmZogvruF3A"
38
+ def self.token
39
+ secure_string
40
+ end
41
+
42
+ # Returns token hash for a token with given cost. If no cost value is specified,
43
+ # the default value is used. The possible cost value is within range from 4 to 31.
44
+ # It is recommended to not use a value more than 10.
45
+ # Example:
46
+ # DeviseTokens::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q")
47
+ # => "$2a$10$6/cTAtQ3CBLfpkeHW7dlt.PD2aVCbFRN5vDDJUUhGsZ6pzYFlh4Me"
48
+ #
49
+ # DeviseTokens::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q", 4)
50
+ # => "$2a$04$RkIrosbdRtuet2eUk3si8eS4ufeNpiPc/rSSsfpniRK8ogM5YFOWS"
51
+ def self.token_hash(token, cost = nil)
52
+ cost ||= DeviseTokens.token_cost
53
+ BCrypt::Password.create(token, cost: cost)
54
+ end
55
+
56
+ # Returns the value of time as an integer number of seconds. Takes one argument.
57
+ # Example:
58
+ # DeviseTokens::TokenFactory.expiry
59
+ # => 1518983359
60
+ # DeviseTokens::TokenFactory.expiry(10)
61
+ # => 1517773781
62
+ def self.expiry(lifespan = nil)
63
+ lifespan ||= DeviseTokens.token_lifespan
64
+ (Time.zone.now + lifespan).to_i
65
+ end
66
+
67
+ # Generates a random URL-safe string.
68
+ # Example:
69
+ # DeviseTokens::TokenFactory.secure_string
70
+ # => "ADBoIaqXsEDnxIpOuumrTA"
71
+ def self.secure_string
72
+ # https://ruby-doc.org/stdlib-2.5.0/libdoc/securerandom/rdoc/Random/Formatter.html#method-i-urlsafe_base64
73
+ SecureRandom.urlsafe_base64
74
+ end
75
+
76
+ # Returns true if token hash is a valid token hash.
77
+ # Example:
78
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
79
+ # DeviseTokens::TokenFactory.valid_token_hash?(token_hash)
80
+ # => true
81
+ def self.valid_token_hash?(token_hash)
82
+ !!BCrypt::Password.valid_hash?(token_hash)
83
+ end
84
+
85
+ # Compares a potential token against the token hash. Returns true if the token is the original token, false otherwise.
86
+ # Example:
87
+ # token = "4wZ9gcc900rMQD1McpcSNA"
88
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
89
+ # DeviseTokens::TokenFactory.token_hash_is_token?(token_hash, token)
90
+ # => true
91
+ def self.token_hash_is_token?(token_hash, token)
92
+ BCrypt::Password.new(token_hash).is_password?(token)
93
+ rescue StandardError
94
+ false
95
+ end
96
+
97
+ # Creates a token instance with instance variables equal nil.
98
+ # Example:
99
+ # DeviseTokens::TokenFactory.new
100
+ # => #<struct DeviseTokens::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
101
+ def self.new
102
+ Token.new
103
+ end
104
+
105
+ Token = Struct.new(:client, :token, :token_hash, :expiry) do
106
+ # Sets all instance variables of the token to nil. It is faster than creating new empty token.
107
+ # Example:
108
+ # token.clear!
109
+ # => true
110
+ # token
111
+ # => #<struct DeviseTokens::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
112
+ def clear!
113
+ size.times { |i| self[i] = nil }
114
+ true
115
+ end
116
+
117
+ # Checks token attribute presence
118
+ # Example:
119
+ # token.present?
120
+ # => true
121
+ def present?
122
+ token.present?
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,39 @@
1
+ module DeviseTokens::Url
2
+
3
+ def self.generate(url, params = {})
4
+ uri = URI(url)
5
+
6
+ res = "#{uri.scheme}://#{uri.host}"
7
+ res += ":#{uri.port}" if (uri.port && uri.port != 80 && uri.port != 443)
8
+ res += uri.path.to_s if uri.path
9
+ query = [uri.query, params.to_query].reject(&:blank?).join('&')
10
+ res += "?#{query}"
11
+ res += "##{uri.fragment}" if uri.fragment
12
+
13
+ res
14
+ end
15
+
16
+ def self.whitelisted?(url)
17
+ url.nil? || \
18
+ !!DeviseTokens.redirect_whitelist.find do |pattern|
19
+ !!Wildcat.new(pattern).match(url)
20
+ end
21
+ end
22
+
23
+ # wildcard convenience class
24
+ class Wildcat
25
+ def self.parse_to_regex(str)
26
+ escaped = Regexp.escape(str).gsub('\*','.*?')
27
+ Regexp.new("^#{escaped}$", Regexp::IGNORECASE)
28
+ end
29
+
30
+ def initialize(str)
31
+ @regex = self.class.parse_to_regex(str)
32
+ end
33
+
34
+ def match(str)
35
+ !!@regex.match(str)
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,3 @@
1
+ module DeviseTokens
2
+ VERSION = '1.1.3'.freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ Description:
2
+ This generator will install all the necessary configuration and migration
3
+ files for the devise_tokens gem. See
4
+ https://github.com/lynndylanhurley/devise_tokens for more information.
5
+
6
+ Arguments:
7
+ USER_CLASS # The name of the class to use for user authentication. Default is
8
+ # 'User'
9
+ MOUNT_PATH # The path at which to mount the authentication routes. Default is
10
+ # 'auth'. More detail documentation is here:
11
+ # https://github.com/lynndylanhurley/devise_tokens#usage-tldr
12
+
13
+ Example:
14
+ rails generate devise_tokens:install User auth
15
+
16
+ This will create:
17
+ config/initializers/devise_tokens.rb
18
+ db/migrate/<%= Time.zone.now.utc.strftime("%Y%m%d%H%M%S") %>_create_devise_tokens_create_users.rb
19
+ app/models/user.rb
20
+
21
+ If 'app/models/user.rb' already exists, the following line will be inserted
22
+ after the class definition:
23
+ include DeviseTokens::Concerns::User
24
+
25
+ The following line will be inserted into your application controller at
26
+ app/controllers/application_controller.rb:
27
+ include DeviseTokens::Concerns::SetUserByToken
28
+
29
+ The following line will be inserted at the top of 'config/routes.rb' if it
30
+ does not already exist:
31
+ mount_devise_tokens_for "User", at: 'auth'
@@ -0,0 +1,91 @@
1
+
2
+
3
+ require_relative 'install_generator_helpers'
4
+
5
+ module DeviseTokens
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ include DeviseTokens::InstallGeneratorHelpers
9
+
10
+ class_option :primary_key_type, type: :string, desc: 'The type for primary key'
11
+
12
+ def copy_migrations
13
+ if self.class.migration_exists?('db/migrate', "devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}")
14
+ say_status('skipped', "Migration 'devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}' already exists")
15
+ else
16
+ migration_template(
17
+ 'devise_tokens_create_users.rb.erb',
18
+ "db/migrate/devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}.rb"
19
+ )
20
+ end
21
+ end
22
+
23
+ def create_user_model
24
+ fname = "app/models/#{user_class.underscore}.rb"
25
+ if File.exist?(File.join(destination_root, fname))
26
+ inclusion = 'include DeviseTokens::Concerns::User'
27
+ unless parse_file_for_line(fname, inclusion)
28
+
29
+ active_record_needle = (Rails::VERSION::MAJOR == 5) ? 'ApplicationRecord' : 'ActiveRecord::Base'
30
+ inject_into_file fname, after: "class #{user_class} < #{active_record_needle}\n" do <<-'RUBY'
31
+ # Include default devise modules.
32
+ devise :database_authenticatable, :registerable,
33
+ :recoverable, :rememberable, :trackable, :validatable,
34
+ :confirmable, :omniauthable
35
+ include DeviseTokens::Concerns::User
36
+ RUBY
37
+ end
38
+ end
39
+ else
40
+ template('user.rb.erb', fname)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def self.next_migration_number(path)
47
+ Time.zone.now.utc.strftime('%Y%m%d%H%M%S')
48
+ end
49
+
50
+ def json_supported_database?
51
+ (postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?)
52
+ end
53
+
54
+ def postgres?
55
+ database_name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
56
+ end
57
+
58
+ def postgres_correct_version?
59
+ database_version > '9.3'
60
+ end
61
+
62
+ def mysql?
63
+ database_name == 'ActiveRecord::ConnectionAdapters::MysqlAdapter'
64
+ end
65
+
66
+ def mysql_correct_version?
67
+ database_version > '5.7.7'
68
+ end
69
+
70
+ def database_name
71
+ ActiveRecord::Base.connection.class.name
72
+ end
73
+
74
+ def database_version
75
+ ActiveRecord::Base.connection.select_value('SELECT VERSION()')
76
+ end
77
+
78
+ def rails5?
79
+ Rails.version.start_with? '5'
80
+ end
81
+
82
+ def primary_key_type
83
+ primary_key_string if rails5?
84
+ end
85
+
86
+ def primary_key_string
87
+ key_string = options[:primary_key_type]
88
+ ", id: :#{key_string}" if key_string
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,98 @@
1
+ module DeviseTokens
2
+ module InstallGeneratorHelpers
3
+ class << self
4
+ def included(mod)
5
+ mod.class_eval do
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ argument :user_class, type: :string, default: 'User'
9
+ argument :mount_path, type: :string, default: 'auth'
10
+
11
+ def create_initializer_file
12
+ copy_file('devise_tokens.rb', 'config/initializers/devise_tokens.rb')
13
+ end
14
+
15
+ def include_controller_concerns
16
+ fname = 'app/controllers/application_controller.rb'
17
+ line = 'include DeviseTokens::Concerns::SetUserByToken'
18
+
19
+ if File.exist?(File.join(destination_root, fname))
20
+ if parse_file_for_line(fname, line)
21
+ say_status('skipped', 'Concern is already included in the application controller.')
22
+ elsif is_rails_api?
23
+ inject_into_file fname, after: "class ApplicationController < ActionController::API\n" do <<-'RUBY'
24
+ include DeviseTokens::Concerns::SetUserByToken
25
+ RUBY
26
+ end
27
+ else
28
+ inject_into_file fname, after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY'
29
+ include DeviseTokens::Concerns::SetUserByToken
30
+ RUBY
31
+ end
32
+ end
33
+ else
34
+ say_status('skipped', "app/controllers/application_controller.rb not found. Add 'include DeviseTokens::Concerns::SetUserByToken' to any controllers that require authentication.")
35
+ end
36
+ end
37
+
38
+ def add_route_mount
39
+ f = 'config/routes.rb'
40
+ str = "mount_devise_tokens_for '#{user_class}', at: '#{mount_path}'"
41
+
42
+ if File.exist?(File.join(destination_root, f))
43
+ line = parse_file_for_line(f, 'mount_devise_tokens_for')
44
+
45
+ if line
46
+ existing_user_class = true
47
+ else
48
+ line = 'Rails.application.routes.draw do'
49
+ existing_user_class = false
50
+ end
51
+
52
+ if parse_file_for_line(f, str)
53
+ say_status('skipped', "Routes already exist for #{user_class} at #{mount_path}")
54
+ else
55
+ insert_after_line(f, line, str)
56
+
57
+ if existing_user_class
58
+ scoped_routes = ''\
59
+ "as :#{user_class.underscore} do\n"\
60
+ " # Define routes for #{user_class} within this block.\n"\
61
+ " end\n"
62
+ insert_after_line(f, str, scoped_routes)
63
+ end
64
+ end
65
+ else
66
+ say_status('skipped', "config/routes.rb not found. Add \"mount_devise_tokens_for '#{user_class}', at: '#{mount_path}'\" to your routes file.")
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def insert_after_line(filename, line, str)
73
+ gsub_file filename, /(#{Regexp.escape(line)})/mi do |match|
74
+ "#{match}\n #{str}"
75
+ end
76
+ end
77
+
78
+ def parse_file_for_line(filename, str)
79
+ match = false
80
+
81
+ File.open(File.join(destination_root, filename)) do |f|
82
+ f.each_line do |line|
83
+ match = line if line =~ /(#{Regexp.escape(str)})/mi
84
+ end
85
+ end
86
+ match
87
+ end
88
+
89
+ def is_rails_api?
90
+ fname = 'app/controllers/application_controller.rb'
91
+ line = 'class ApplicationController < ActionController::API'
92
+ parse_file_for_line(fname, line)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end