orats 0.2.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 +7 -0
- data/.gitignore +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +199 -0
- data/Rakefile +1 -0
- data/bin/orats +17 -0
- data/lib/orats.rb +5 -0
- data/lib/orats/cli.rb +89 -0
- data/lib/orats/server.rb +50 -0
- data/lib/orats/shell.rb +49 -0
- data/lib/orats/templates/commands/auth.rb +853 -0
- data/lib/orats/templates/commands/base.rb +809 -0
- data/lib/orats/templates/includes/Gemfile +46 -0
- data/lib/orats/version.rb +3 -0
- data/orats.gemspec +25 -0
- metadata +104 -0
@@ -0,0 +1,853 @@
|
|
1
|
+
# =====================================================================================================
|
2
|
+
# Template for generating authentication and authorization on top of the base template
|
3
|
+
# =====================================================================================================
|
4
|
+
|
5
|
+
# ----- Helper functions and variables ----------------------------------------------------------------
|
6
|
+
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
def generate_token
|
10
|
+
SecureRandom.hex(64)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_migration(table_name, migration='')
|
14
|
+
utc_now = Time.now.getutc.strftime("%Y%m%d%H%M%S")
|
15
|
+
class_name = table_name.to_s.classify.pluralize
|
16
|
+
|
17
|
+
file "db/migrate/#{utc_now}_create_#{table_name}.rb", %{
|
18
|
+
class Create#{class_name} < ActiveRecord::Migration
|
19
|
+
def change
|
20
|
+
#{migration}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
app_name_upper = app_name.upcase
|
27
|
+
|
28
|
+
# ----- Delete application.css ------------------------------------------------------------------------
|
29
|
+
|
30
|
+
# This gets created by rails automatically when you make a new project
|
31
|
+
run 'rm -f app/assets/stylesheets/application.css'
|
32
|
+
|
33
|
+
# ----- Modify Gemfile --------------------------------------------------------------------------------
|
34
|
+
|
35
|
+
puts
|
36
|
+
say_status 'root', 'Modifying Gemfile..', :yellow
|
37
|
+
puts '-'*80, ''; sleep 0.25
|
38
|
+
|
39
|
+
inject_into_file 'Gemfile', before: "\ngem 'kaminari'" do <<-CODE
|
40
|
+
|
41
|
+
gem 'devise', '~> 3.2.2'
|
42
|
+
gem 'devise-async', '~> 0.9.0'
|
43
|
+
gem 'pundit', '~> 0.2.1'
|
44
|
+
CODE
|
45
|
+
end
|
46
|
+
|
47
|
+
git add: '.'
|
48
|
+
git commit: "-m 'Add devise, devise-async and pundit gems'"
|
49
|
+
|
50
|
+
# ----- Run bundle install ----------------------------------------------------------------------------
|
51
|
+
|
52
|
+
puts
|
53
|
+
say_status 'action', 'Running bundle install, it should not take too long', :yellow
|
54
|
+
puts '-'*80, ''; sleep 0.25
|
55
|
+
|
56
|
+
run 'bundle install'
|
57
|
+
|
58
|
+
# ----- Modify sidekiq config -------------------------------------------------------------------------
|
59
|
+
|
60
|
+
puts
|
61
|
+
say_status 'config', 'Modifying the sidekiq config', :yellow
|
62
|
+
puts '-'*80, ''; sleep 0.25
|
63
|
+
|
64
|
+
append_file 'config/sidekiq.yml' do <<-FILE
|
65
|
+
- mailer
|
66
|
+
FILE
|
67
|
+
end
|
68
|
+
|
69
|
+
git add: '.'
|
70
|
+
git commit: "-m 'Add the devise mailer queue to the sidekiq config'"
|
71
|
+
|
72
|
+
# ----- Create the account fixtures -------------------------------------------------------------------
|
73
|
+
|
74
|
+
puts
|
75
|
+
say_status 'test', 'Creating the account fixtures...', :yellow
|
76
|
+
puts '-'*80, ''; sleep 0.25
|
77
|
+
|
78
|
+
file 'test/fixtures/accounts.yml' do <<-'CODE'
|
79
|
+
foo:
|
80
|
+
id: 1
|
81
|
+
email: foo@bar.com
|
82
|
+
encrypted_password: passwordisnotreallyencrypted
|
83
|
+
role: admin
|
84
|
+
created_at: 2012-01-01 01:45:17
|
85
|
+
current_sign_in_at: 2013-03-15 11:22:33
|
86
|
+
|
87
|
+
no_role:
|
88
|
+
id: 2
|
89
|
+
email: joey@almostcool.com
|
90
|
+
encrypted_password: hackthegibson
|
91
|
+
created_at: 1995-09-15 08:10:12
|
92
|
+
|
93
|
+
bad_role:
|
94
|
+
id: 3
|
95
|
+
email: hello@world.com
|
96
|
+
encrypted_password: reallysecure
|
97
|
+
role: ahhhh
|
98
|
+
created_at: 2011-09-20 10:10:10
|
99
|
+
|
100
|
+
beep:
|
101
|
+
id: 4
|
102
|
+
email: beep@beep.com
|
103
|
+
encrypted_password: beepbeepbeep
|
104
|
+
created_at: 2010-03-6 05:15:45
|
105
|
+
CODE
|
106
|
+
end
|
107
|
+
|
108
|
+
git add: '.'
|
109
|
+
git commit: "-m 'Add the account model'"
|
110
|
+
|
111
|
+
# ----- Modify the test helper ------------------------------------------------------------------------
|
112
|
+
|
113
|
+
puts
|
114
|
+
say_status 'test', 'Modifying the test helper...', :yellow
|
115
|
+
puts '-'*80, ''; sleep 0.25
|
116
|
+
|
117
|
+
inject_into_file 'test/test_helper.rb', after: "end\n" do <<-CODE
|
118
|
+
|
119
|
+
class ActionController::TestCase
|
120
|
+
include Devise::TestHelpers
|
121
|
+
end
|
122
|
+
CODE
|
123
|
+
end
|
124
|
+
|
125
|
+
git add: '.'
|
126
|
+
git commit: "-m 'Add the devise helpers to test helper'"
|
127
|
+
|
128
|
+
# ----- Create the account unit tests -----------------------------------------------------------------
|
129
|
+
|
130
|
+
puts
|
131
|
+
say_status 'test', 'Creating the account unit tests...', :yellow
|
132
|
+
puts '-'*80, ''; sleep 0.25
|
133
|
+
|
134
|
+
file 'test/models/account_test.rb' do <<-'CODE'
|
135
|
+
require 'test_helper'
|
136
|
+
|
137
|
+
class AccountTest < ActiveSupport::TestCase
|
138
|
+
def setup
|
139
|
+
@account = accounts(:foo)
|
140
|
+
end
|
141
|
+
|
142
|
+
def teardown
|
143
|
+
@account = nil
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'expect new account' do
|
147
|
+
assert @account.valid?
|
148
|
+
assert_not_nil @account.email
|
149
|
+
assert_not_nil @account.encrypted_password
|
150
|
+
end
|
151
|
+
|
152
|
+
test 'expect guest to be default role' do
|
153
|
+
no_role = accounts(:no_role)
|
154
|
+
assert_equal 'guest', no_role.role
|
155
|
+
end
|
156
|
+
|
157
|
+
test 'expect invalid role to not save' do
|
158
|
+
bad_role = accounts(:bad_role)
|
159
|
+
assert_not bad_role.valid?
|
160
|
+
end
|
161
|
+
|
162
|
+
test 'expect e-mail to be unique' do
|
163
|
+
duplicate = Account.create(email: 'foo@bar.com')
|
164
|
+
|
165
|
+
assert_not duplicate.valid?
|
166
|
+
end
|
167
|
+
|
168
|
+
test 'expect random password if password is empty' do
|
169
|
+
@account.password = ''
|
170
|
+
@account.encrypted_password = ''
|
171
|
+
@account.save
|
172
|
+
|
173
|
+
random_password = Account.generate_password
|
174
|
+
assert_equal 10, random_password.length
|
175
|
+
end
|
176
|
+
|
177
|
+
test 'expect random password of 20 characters' do
|
178
|
+
assert_equal 20, Account.generate_password(20).length
|
179
|
+
end
|
180
|
+
end
|
181
|
+
CODE
|
182
|
+
end
|
183
|
+
|
184
|
+
git add: '.'
|
185
|
+
git commit: "-m 'Add the account unit tests'"
|
186
|
+
|
187
|
+
# ----- Create the account model ----------------------------------------------------------------------
|
188
|
+
|
189
|
+
puts
|
190
|
+
say_status 'models', 'Creating the account model...', :yellow
|
191
|
+
puts '-'*80, ''; sleep 0.25
|
192
|
+
|
193
|
+
file 'app/models/account.rb' do <<-'CODE'
|
194
|
+
class Account < ActiveRecord::Base
|
195
|
+
ROLES = %w[admin guest]
|
196
|
+
|
197
|
+
devise :database_authenticatable, :registerable, :recoverable, :rememberable,
|
198
|
+
:trackable, :timeoutable, :lockable, :validatable, :async
|
199
|
+
|
200
|
+
before_validation :ensure_password, on: :create
|
201
|
+
|
202
|
+
after_save :invalidate_cache
|
203
|
+
|
204
|
+
validates :role, inclusion: { in: ROLES }
|
205
|
+
|
206
|
+
def self.serialize_from_session(key, salt)
|
207
|
+
# store the current_account in the cache so we do not perform a db lookup on each authenticated page
|
208
|
+
single_key = key.is_a?(Array) ? key.first : key
|
209
|
+
|
210
|
+
Rails.cache.fetch("account:#{single_key}") do
|
211
|
+
Account.where(id: single_key).entries.first
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.generate_password(length = 10)
|
216
|
+
Devise.friendly_token.first(length)
|
217
|
+
end
|
218
|
+
|
219
|
+
def is?(role_check)
|
220
|
+
role.to_sym == role_check
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def ensure_password
|
226
|
+
# only generate a password if it does not exist
|
227
|
+
self.password ||= Account.generate_password
|
228
|
+
end
|
229
|
+
|
230
|
+
def invalidate_cache
|
231
|
+
Rails.cache.delete("account:#{id}")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
CODE
|
235
|
+
end
|
236
|
+
|
237
|
+
git add: '.'
|
238
|
+
git commit: "-m 'Add the account model'"
|
239
|
+
|
240
|
+
# ----- Create devise migration -----------------------------------------------------------------------
|
241
|
+
|
242
|
+
puts
|
243
|
+
say_status 'db', 'Creating devise model migration...', :yellow
|
244
|
+
puts '-'*80, ''; sleep 0.25
|
245
|
+
|
246
|
+
create_migration :accounts, %{
|
247
|
+
create_table(:accounts) do |t|
|
248
|
+
## Database authenticatable
|
249
|
+
t.string :email, :null => false, :default => ''
|
250
|
+
t.string :encrypted_password, :null => false, :default => ''
|
251
|
+
|
252
|
+
## Recoverable
|
253
|
+
t.string :reset_password_token
|
254
|
+
t.datetime :reset_password_sent_at
|
255
|
+
|
256
|
+
## Rememberable
|
257
|
+
t.datetime :remember_created_at
|
258
|
+
|
259
|
+
## Trackable
|
260
|
+
t.integer :sign_in_count, :default => 0, :null => false
|
261
|
+
t.datetime :current_sign_in_at
|
262
|
+
t.datetime :last_sign_in_at
|
263
|
+
t.string :current_sign_in_ip
|
264
|
+
t.string :last_sign_in_ip
|
265
|
+
|
266
|
+
## Lockable
|
267
|
+
t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
|
268
|
+
t.string :unlock_token # Only if unlock strategy is :email or :both
|
269
|
+
t.datetime :locked_at
|
270
|
+
|
271
|
+
## Role
|
272
|
+
t.string :role, default: 'guest'
|
273
|
+
|
274
|
+
t.timestamps
|
275
|
+
end
|
276
|
+
|
277
|
+
add_index :accounts, :email, :unique => true
|
278
|
+
add_index :accounts, :reset_password_token, :unique => true
|
279
|
+
add_index :accounts, :unlock_token, :unique => true
|
280
|
+
}
|
281
|
+
|
282
|
+
git add: '.'
|
283
|
+
git commit: "-m 'Add devise model migration'"
|
284
|
+
|
285
|
+
# ----- Create a seed user ----------------------------------------------------------------------------
|
286
|
+
|
287
|
+
puts
|
288
|
+
say_status 'db', 'Creating a seed user...', :yellow
|
289
|
+
puts '-'*80, ''; sleep 0.25
|
290
|
+
|
291
|
+
append_file 'db/seeds.rb', "\nAccount.create({ email: \"admin@#{app_name}.com\", password: \"password\", role: \"admin\" })"
|
292
|
+
|
293
|
+
git add: '.'
|
294
|
+
git commit: "-m 'Add a seed user'"
|
295
|
+
|
296
|
+
# ----- Create en i18n entries ------------------------------------------------------------------------
|
297
|
+
|
298
|
+
puts
|
299
|
+
say_status 'db', 'Creating en i18n entries...', :yellow
|
300
|
+
puts '-'*80, ''; sleep 0.25
|
301
|
+
|
302
|
+
gsub_file 'config/locales/en.yml', "hello: \"Hello world\"\n", ''
|
303
|
+
|
304
|
+
append_file 'config/locales/en.yml' do <<-CODE
|
305
|
+
authorization:
|
306
|
+
error: 'You are not authorized to perform this action.'
|
307
|
+
CODE
|
308
|
+
end
|
309
|
+
|
310
|
+
git add: '.'
|
311
|
+
git commit: "-m 'Add en i18n entries'"
|
312
|
+
|
313
|
+
# ----- Modify the application controller -------------------------------------------------------------
|
314
|
+
|
315
|
+
puts
|
316
|
+
say_status 'db', 'Modifying the application controller...', :yellow
|
317
|
+
puts '-'*80, ''; sleep 0.25
|
318
|
+
|
319
|
+
inject_into_file 'app/controllers/application_controller.rb', after: "::Base\n" do <<-'CODE'
|
320
|
+
alias_method :current_user, :current_account
|
321
|
+
|
322
|
+
CODE
|
323
|
+
end
|
324
|
+
|
325
|
+
git add: '.'
|
326
|
+
git commit: "-m 'Alias current_user to current_account to play nice with other gems'"
|
327
|
+
|
328
|
+
inject_into_file 'app/controllers/application_controller.rb', before: "end\n" do <<-'CODE'
|
329
|
+
|
330
|
+
private
|
331
|
+
|
332
|
+
# Override devise to customize the after sign in path.
|
333
|
+
#def after_sign_in_path_for(resource)
|
334
|
+
# if resource.is? :admin
|
335
|
+
# admin_path
|
336
|
+
# else
|
337
|
+
# somewhere_path
|
338
|
+
# end
|
339
|
+
#end
|
340
|
+
CODE
|
341
|
+
end
|
342
|
+
|
343
|
+
git add: '.'
|
344
|
+
git commit: "-m 'Change the application controller to allow overriding the devise sign in path'"
|
345
|
+
|
346
|
+
# ----- Create the devise views -----------------------------------------------------------------------
|
347
|
+
|
348
|
+
puts
|
349
|
+
say_status 'views', 'Creating the devise views...', :yellow
|
350
|
+
puts '-'*80, ''; sleep 0.25
|
351
|
+
|
352
|
+
file 'app/views/devise/confirmations/new.html.erb' do <<-HTML
|
353
|
+
<%
|
354
|
+
title 'Confirm'
|
355
|
+
meta_description '...'
|
356
|
+
heading 'Confirm'
|
357
|
+
%>
|
358
|
+
|
359
|
+
<div class="row">
|
360
|
+
<div class="col-sm-4">
|
361
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
362
|
+
<div class="form-group">
|
363
|
+
<%= f.label :email %>
|
364
|
+
<%= f.email_field :email, class: 'form-control', maxlength: 254, autofocus: true,
|
365
|
+
data: {
|
366
|
+
'rule-required' => 'true',
|
367
|
+
'rule-maxlength' => '254'
|
368
|
+
} %>
|
369
|
+
</div>
|
370
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
371
|
+
Send
|
372
|
+
<% end %>
|
373
|
+
<% end %>
|
374
|
+
</div>
|
375
|
+
<div class="col-sm-6 col-sm-offset-2">
|
376
|
+
<%= render 'devise/shared/links' %>
|
377
|
+
</div>
|
378
|
+
</div>
|
379
|
+
HTML
|
380
|
+
end
|
381
|
+
|
382
|
+
file 'app/views/devise/mailer/confirmation_instructions.html.erb' do <<-HTML
|
383
|
+
<p>Welcome <%= @email %>!</p>
|
384
|
+
|
385
|
+
<p>You can confirm your account email through the link below:</p>
|
386
|
+
|
387
|
+
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
|
388
|
+
HTML
|
389
|
+
end
|
390
|
+
|
391
|
+
file 'app/views/devise/mailer/reset_password_instructions.html.erb' do <<-HTML
|
392
|
+
<p>Hello <%= @resource.email %>!</p>
|
393
|
+
|
394
|
+
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
395
|
+
|
396
|
+
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
397
|
+
|
398
|
+
<p>If you didn't request this, please ignore this email.</p>
|
399
|
+
<p>Your password won't change until you access the link above and create a new one.</p>
|
400
|
+
HTML
|
401
|
+
end
|
402
|
+
|
403
|
+
file 'app/views/devise/mailer/unlock_instructions.html.erb' do <<-HTML
|
404
|
+
<p>Hello <%= @resource.email %>!</p>
|
405
|
+
|
406
|
+
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
407
|
+
|
408
|
+
<p>Click the link below to unlock your account:</p>
|
409
|
+
|
410
|
+
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
411
|
+
HTML
|
412
|
+
end
|
413
|
+
|
414
|
+
file 'app/views/devise/passwords/edit.html.erb' do <<-HTML
|
415
|
+
<%
|
416
|
+
title 'Change your password'
|
417
|
+
meta_description '...'
|
418
|
+
heading 'Change your password'
|
419
|
+
%>
|
420
|
+
|
421
|
+
<div class="row">
|
422
|
+
<div class="col-sm-4">
|
423
|
+
<%= form_for resource, as: resource_name, url: password_path(resource_name), html: { method: :put } do |f| %>
|
424
|
+
<%= f.hidden_field :reset_password_token %>
|
425
|
+
<div class="form-group">
|
426
|
+
<%= f.label :password, 'New password' %>
|
427
|
+
<%= f.password_field :password, maxlength: 128, class: 'form-control', autofocus: true,
|
428
|
+
data: {
|
429
|
+
'rule-required' => 'true',
|
430
|
+
'rule-minlength' => '8',
|
431
|
+
'rule-maxlength' => '128'
|
432
|
+
} %>
|
433
|
+
</div>
|
434
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
435
|
+
Send
|
436
|
+
<% end %>
|
437
|
+
<% end %>
|
438
|
+
</div>
|
439
|
+
<div class="col-sm-6 col-sm-offset-2">
|
440
|
+
<%= render 'devise/shared/links' %>
|
441
|
+
</div>
|
442
|
+
</div>
|
443
|
+
HTML
|
444
|
+
end
|
445
|
+
|
446
|
+
file 'app/views/devise/passwords/new.html.erb' do <<-HTML
|
447
|
+
<%
|
448
|
+
title 'Forgot your password?'
|
449
|
+
meta_description '...'
|
450
|
+
heading 'Forgot your password?'
|
451
|
+
%>
|
452
|
+
|
453
|
+
<div class="row">
|
454
|
+
<div class="col-sm-4">
|
455
|
+
<%= form_for resource, as: resource_name, url: password_path(resource_name), html: { method: :post } do |f| %>
|
456
|
+
<div class="form-group">
|
457
|
+
<%= f.label :email %>
|
458
|
+
<%= f.email_field :email, class: 'form-control', autofocus: true, maxlength: 254,
|
459
|
+
data: {
|
460
|
+
'rule-required' => 'true',
|
461
|
+
'rule-maxlength' => '254'
|
462
|
+
} %>
|
463
|
+
</div>
|
464
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
465
|
+
Send
|
466
|
+
<% end %>
|
467
|
+
<% end %>
|
468
|
+
</div>
|
469
|
+
<div class="col-sm-6 col-sm-offset-2">
|
470
|
+
<%= render 'devise/shared/links' %>
|
471
|
+
</div>
|
472
|
+
</div>
|
473
|
+
HTML
|
474
|
+
end
|
475
|
+
|
476
|
+
file 'app/views/devise/registrations/edit.html.erb' do <<-HTML
|
477
|
+
<%
|
478
|
+
title 'Edit your account'
|
479
|
+
meta_description '...'
|
480
|
+
heading 'Edit your account'
|
481
|
+
%>
|
482
|
+
|
483
|
+
<div class="row">
|
484
|
+
<div class="col-sm-6">
|
485
|
+
<%= form_for resource, as: resource_name, url: registration_path(resource_name), html: { method: :patch } do |f| %>
|
486
|
+
<div class="form-group">
|
487
|
+
<%= f.label :current_password %>
|
488
|
+
<span class="help-block form-help-adjust-margin">
|
489
|
+
<small>
|
490
|
+
Supply your current password to make any changes
|
491
|
+
</small>
|
492
|
+
</span>
|
493
|
+
<%= f.password_field :current_password, maxlength: 128, class: 'form-control',
|
494
|
+
data: {
|
495
|
+
'rule-required' => 'true',
|
496
|
+
'rule-minlength' => '8',
|
497
|
+
'rule-maxlength' => '128'
|
498
|
+
} %>
|
499
|
+
</div>
|
500
|
+
<div class="form-group">
|
501
|
+
<%= f.label :email %>
|
502
|
+
<%= f.email_field :email, class: 'form-control', maxlength: 254, autofocus: true %>
|
503
|
+
</div>
|
504
|
+
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
505
|
+
<h3>Currently waiting confirmation for: <%= resource.unconfirmed_email %></h3>
|
506
|
+
<% end %>
|
507
|
+
<div class="form-group">
|
508
|
+
<%= f.label :password %>
|
509
|
+
<span class="help-block form-help-adjust-margin">
|
510
|
+
<small>
|
511
|
+
Leave this blank if you do not want to change it
|
512
|
+
</small>
|
513
|
+
</span>
|
514
|
+
<%= f.password_field :password, class: 'form-control' %>
|
515
|
+
</div>
|
516
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
517
|
+
Save
|
518
|
+
<% end %>
|
519
|
+
<% end %>
|
520
|
+
</div>
|
521
|
+
<div class="col-sm-6">
|
522
|
+
<p>
|
523
|
+
Unhappy? <%= button_to 'Cancel my account', registration_path(resource_name), method: :delete %>
|
524
|
+
</p>
|
525
|
+
</div>
|
526
|
+
</div>
|
527
|
+
HTML
|
528
|
+
end
|
529
|
+
|
530
|
+
file 'app/views/devise/registrations/new.html.erb' do <<-HTML
|
531
|
+
<%
|
532
|
+
title 'Register a new account'
|
533
|
+
meta_description '...'
|
534
|
+
heading 'Register a new account'
|
535
|
+
%>
|
536
|
+
|
537
|
+
<div class="row">
|
538
|
+
<div class="col-sm-4">
|
539
|
+
<%= form_for resource, as: resource_name, url: registration_path(resource_name) do |f| %>
|
540
|
+
<div class="form-group">
|
541
|
+
<%= f.label :email %>
|
542
|
+
<%= f.email_field :email, class: 'form-control', maxlength: 254, autofocus: true %>
|
543
|
+
</div>
|
544
|
+
<div class="form-group">
|
545
|
+
<%= f.label :password %>
|
546
|
+
<%= f.password_field :password, maxlength: 128, class: 'form-control',
|
547
|
+
data: {
|
548
|
+
'rule-required' => 'true',
|
549
|
+
'rule-minlength' => '8',
|
550
|
+
'rule-maxlength' => '128'
|
551
|
+
} %>
|
552
|
+
</div>
|
553
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
554
|
+
Register
|
555
|
+
<% end %>
|
556
|
+
<% end %>
|
557
|
+
</div>
|
558
|
+
<div class="col-sm-6 col-sm-offset-2">
|
559
|
+
<%= render 'devise/shared/links' %>
|
560
|
+
</div>
|
561
|
+
</div>
|
562
|
+
HTML
|
563
|
+
end
|
564
|
+
|
565
|
+
file 'app/views/devise/sessions/new.html.erb' do <<-HTML
|
566
|
+
<%
|
567
|
+
title 'Sign in'
|
568
|
+
meta_description '...'
|
569
|
+
heading 'Sign in'
|
570
|
+
%>
|
571
|
+
|
572
|
+
<div class="row">
|
573
|
+
<div class="col-sm-4">
|
574
|
+
<%= form_for resource, as: resource_name, url: session_path(resource_name) do |f| %>
|
575
|
+
<div class="form-group">
|
576
|
+
<%= f.label :email %>
|
577
|
+
<%= f.email_field :email, maxlength: 254, class: 'form-control', autofocus: true %>
|
578
|
+
</div>
|
579
|
+
<div class="form-group">
|
580
|
+
<%= f.label :password %>
|
581
|
+
<%= f.password_field :password, maxlength: 128, class: 'form-control',
|
582
|
+
data: {
|
583
|
+
'rule-required' => 'true',
|
584
|
+
'rule-minlength' => '8',
|
585
|
+
'rule-maxlength' => '128'
|
586
|
+
} %>
|
587
|
+
</div>
|
588
|
+
<% if devise_mapping.rememberable? -%>
|
589
|
+
<div class="checkbox">
|
590
|
+
<%= f.label :remember_me do %>
|
591
|
+
<%= f.check_box :remember_me %> Stay signed in
|
592
|
+
<% end %>
|
593
|
+
</div>
|
594
|
+
<% end -%>
|
595
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
596
|
+
Sign in
|
597
|
+
<% end %>
|
598
|
+
<% end %>
|
599
|
+
</div>
|
600
|
+
<div class="col-sm-6 col-sm-offset-2">
|
601
|
+
<h4 class="success-color">Having trouble accessing your account?</h4>
|
602
|
+
<%= render 'devise/shared/links' %>
|
603
|
+
</div>
|
604
|
+
</div>
|
605
|
+
HTML
|
606
|
+
end
|
607
|
+
|
608
|
+
file 'app/views/devise/unlocks/new.html.erb' do <<-HTML
|
609
|
+
<%
|
610
|
+
title 'Re-send unlock instructions'
|
611
|
+
meta_description '...'
|
612
|
+
heading 'Re-send unlock instructions'
|
613
|
+
%>
|
614
|
+
|
615
|
+
<div class="row">
|
616
|
+
<div class="col-sm-4">
|
617
|
+
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
|
618
|
+
<div class="form-group">
|
619
|
+
<%= f.label :email %>
|
620
|
+
<%= f.email_field :email, class: 'form-control', maxlength: 254, autofocus: true,
|
621
|
+
data: {
|
622
|
+
'rule-required' => 'true',
|
623
|
+
'rule-maxlength' => '254'
|
624
|
+
} %>
|
625
|
+
</div>
|
626
|
+
<%= button_tag type: 'submit', class: 'btn btn-primary' do %>
|
627
|
+
Send
|
628
|
+
<% end %>
|
629
|
+
<% end %>
|
630
|
+
</div>
|
631
|
+
<div class="col-sm-6 col-sm-offset-2">
|
632
|
+
<%= render 'devise/shared/links' %>
|
633
|
+
</div>
|
634
|
+
</div>
|
635
|
+
HTML
|
636
|
+
end
|
637
|
+
|
638
|
+
file 'app/views/devise/shared/_links.html.erb' do <<-'HTML'
|
639
|
+
<%= content_tag(:h4, 'Or do something else') if controller_name != 'sessions' %>
|
640
|
+
<ul>
|
641
|
+
<%- if controller_name != 'sessions' %>
|
642
|
+
<li>
|
643
|
+
<%= link_to 'Sign in', new_session_path(resource_name) %>
|
644
|
+
</li>
|
645
|
+
<% end -%>
|
646
|
+
|
647
|
+
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
648
|
+
<li>
|
649
|
+
<%= link_to 'Sign up', new_registration_path(resource_name) %>
|
650
|
+
</li>
|
651
|
+
<% end -%>
|
652
|
+
|
653
|
+
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
654
|
+
<li>
|
655
|
+
<%= link_to 'Forgot your password?', new_password_path(resource_name) %>
|
656
|
+
</li>
|
657
|
+
<% end -%>
|
658
|
+
|
659
|
+
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
660
|
+
<li>
|
661
|
+
<%= link_to 'Re-send confirmation instructions?', new_confirmation_path(resource_name) %>
|
662
|
+
</li>
|
663
|
+
<% end -%>
|
664
|
+
|
665
|
+
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
666
|
+
<li>
|
667
|
+
<%= link_to 'Are you locked out of your account?', new_unlock_path(resource_name) %>
|
668
|
+
</li>
|
669
|
+
<% end -%>
|
670
|
+
|
671
|
+
<%- if devise_mapping.omniauthable? %>
|
672
|
+
<%- resource_class.omniauth_providers.each do |provider| %>
|
673
|
+
<li><%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %></li>
|
674
|
+
<% end -%>
|
675
|
+
<% end -%>
|
676
|
+
</ul>
|
677
|
+
HTML
|
678
|
+
end
|
679
|
+
|
680
|
+
git add: '.'
|
681
|
+
git commit: "-m 'Add the devise views'"
|
682
|
+
|
683
|
+
# ----- Modify the layout files ------------------------------------------------------------------------
|
684
|
+
|
685
|
+
puts
|
686
|
+
say_status 'views', 'Modifying the layout files...', :yellow
|
687
|
+
puts '-'*80, ''; sleep 0.25
|
688
|
+
|
689
|
+
file 'app/views/layouts/_navigation_auth.html.erb', <<-HTML
|
690
|
+
<% if current_account %>
|
691
|
+
<li>
|
692
|
+
<%= link_to 'Settings', edit_account_registration_path %>
|
693
|
+
</li>
|
694
|
+
<li>
|
695
|
+
<%= link_to 'Sign out', destroy_account_session_path, method: :delete %>
|
696
|
+
</li>
|
697
|
+
<% else %>
|
698
|
+
<li>
|
699
|
+
<%= link_to 'Sign in', new_account_session_path %>
|
700
|
+
</li>
|
701
|
+
<li>
|
702
|
+
<%= link_to 'Register', new_account_registration_path %>
|
703
|
+
</li>
|
704
|
+
<% end %>
|
705
|
+
HTML
|
706
|
+
|
707
|
+
inject_into_file 'app/views/layouts/_navigation.html.erb', after: "</ul>\n" do <<-CODE
|
708
|
+
<ul class="nav navbar-nav nav-auth">
|
709
|
+
<%= render 'layouts/navigation_auth' %>
|
710
|
+
</ul>
|
711
|
+
CODE
|
712
|
+
end
|
713
|
+
|
714
|
+
append_file 'app/assets/stylesheets/application.css.scss' do <<-CODE
|
715
|
+
|
716
|
+
@media (min-width: $screen-sm) {
|
717
|
+
.nav-auth {
|
718
|
+
float: right;
|
719
|
+
}
|
720
|
+
}
|
721
|
+
CODE
|
722
|
+
end
|
723
|
+
|
724
|
+
git add: '.'
|
725
|
+
git commit: "-m 'Add account management links to the layout and add the necessary css selectors'"
|
726
|
+
|
727
|
+
# ----- Modify the .env file --------------------------------------------------------------------------
|
728
|
+
|
729
|
+
puts
|
730
|
+
say_status 'root', 'Modifying the .env file...', :yellow
|
731
|
+
puts '-'*80, ''; sleep 0.25
|
732
|
+
|
733
|
+
inject_into_file '.env', before: "\n#{app_name_upper}_SMTP_ADDRESS" do <<-CODE
|
734
|
+
#{app_name_upper}_TOKEN_DEVISE_SECRET: #{generate_token}
|
735
|
+
#{app_name_upper}_TOKEN_DEVISE_PEPPER: #{generate_token}
|
736
|
+
CODE
|
737
|
+
end
|
738
|
+
|
739
|
+
inject_into_file '.env', before: "\n#{app_name_upper}_DATABASE_NAME" do <<-CODE
|
740
|
+
#{app_name_upper}_ACTION_MAILER_DEVISE_DEFAULT_EMAIL: info@#{app_name}.com
|
741
|
+
CODE
|
742
|
+
end
|
743
|
+
|
744
|
+
git add: '.'
|
745
|
+
git commit: "-m 'Add the devise tokens and default email to the .env file'"
|
746
|
+
|
747
|
+
# ----- Create the config files -----------------------------------------------------------------------
|
748
|
+
|
749
|
+
puts
|
750
|
+
say_status 'config', 'Creating the devise async initializer...', :yellow
|
751
|
+
puts '-'*80, ''; sleep 0.25
|
752
|
+
|
753
|
+
file 'config/initializers/devise_async.rb', 'Devise::Async.backend = :sidekiq'
|
754
|
+
generate 'devise:install'
|
755
|
+
|
756
|
+
git add: '.'
|
757
|
+
git commit: "-m 'Add the devise and devise async initializers'"
|
758
|
+
|
759
|
+
# ----- Modify the config files -----------------------------------------------------------------------
|
760
|
+
|
761
|
+
puts
|
762
|
+
say_status 'config', 'Modifying the devise initializer...', :yellow
|
763
|
+
puts '-'*80, ''; sleep 0.25
|
764
|
+
|
765
|
+
gsub_file 'config/initializers/devise.rb',
|
766
|
+
"'please-change-me-at-config-initializers-devise@example.com'", "ENV['#{app_name_upper}_ACTION_MAILER_DEVISE_DEFAULT_EMAIL']"
|
767
|
+
gsub_file 'config/initializers/devise.rb', /(?<=key = )'\w{128}'/, "ENV['#{app_name_upper}_TOKEN_DEVISE_SECRET']"
|
768
|
+
gsub_file 'config/initializers/devise.rb', /(?<=pepper = )'\w{128}'/, "ENV['#{app_name_upper}_TOKEN_DEVISE_PEPPER']"
|
769
|
+
|
770
|
+
gsub_file 'config/initializers/devise.rb', '# config.timeout_in = 30.minutes',
|
771
|
+
'config.timeout_in = 2.hours'
|
772
|
+
|
773
|
+
gsub_file 'config/initializers/devise.rb', '# config.expire_auth_token_on_timeout = false',
|
774
|
+
'config.expire_auth_token_on_timeout = true'
|
775
|
+
|
776
|
+
gsub_file 'config/initializers/devise.rb', '# config.lock_strategy = :failed_attempts',
|
777
|
+
'config.lock_strategy = :failed_attempts'
|
778
|
+
|
779
|
+
gsub_file 'config/initializers/devise.rb', '# config.unlock_strategy = :both',
|
780
|
+
'config.unlock_strategy = :both'
|
781
|
+
|
782
|
+
gsub_file 'config/initializers/devise.rb', '# config.maximum_attempts = 20',
|
783
|
+
'config.maximum_attempts = 7'
|
784
|
+
|
785
|
+
gsub_file 'config/initializers/devise.rb', '# config.unlock_in = 1.hour',
|
786
|
+
'config.unlock_in = 2.hours'
|
787
|
+
|
788
|
+
gsub_file 'config/initializers/devise.rb', '# config.last_attempt_warning = false',
|
789
|
+
'config.last_attempt_warning = true'
|
790
|
+
|
791
|
+
git add: '.'
|
792
|
+
git commit: "-m 'Change the devise initializer default values'"
|
793
|
+
|
794
|
+
# ----- Modify the routes file ------------------------------------------------------------------------
|
795
|
+
|
796
|
+
puts
|
797
|
+
say_status 'config', 'Modifying the routes file...', :yellow
|
798
|
+
puts '-'*80, ''; sleep 0.25
|
799
|
+
|
800
|
+
inject_into_file 'config/routes.rb', after: "collection\n end\n" do <<-CODE
|
801
|
+
|
802
|
+
# disable users from being able to register by uncommenting the lines below
|
803
|
+
# get 'accounts/sign_up(.:format)', to: redirect('/')
|
804
|
+
# post 'accounts(.:format)', to: redirect('/')
|
805
|
+
|
806
|
+
# disable users from deleting their own account by uncommenting the line below
|
807
|
+
# delete 'accounts(.:format)', to: redirect('/')
|
808
|
+
|
809
|
+
devise_for :accounts
|
810
|
+
|
811
|
+
authenticate :account, lambda { |account| account.is?(:admin) } do
|
812
|
+
mount Sidekiq::Web => '/sidekiq'
|
813
|
+
end
|
814
|
+
|
815
|
+
CODE
|
816
|
+
end
|
817
|
+
|
818
|
+
git add: '.'
|
819
|
+
git commit: "-m 'Add devise to the routes file'"
|
820
|
+
|
821
|
+
# ----- Add pundit support ----------------------------------------------------------------------------
|
822
|
+
|
823
|
+
puts
|
824
|
+
say_status 'root', 'Adding pundit support...', :yellow
|
825
|
+
puts '-'*80, ''; sleep 0.25
|
826
|
+
|
827
|
+
generate 'pundit:install'
|
828
|
+
|
829
|
+
git add: '.'
|
830
|
+
git commit: "-m 'Add pundit application policy'"
|
831
|
+
|
832
|
+
inject_into_file 'app/controllers/application_controller.rb', after: "::Base\n" do <<-'CODE'
|
833
|
+
include Pundit
|
834
|
+
|
835
|
+
CODE
|
836
|
+
end
|
837
|
+
|
838
|
+
inject_into_file 'app/controllers/application_controller.rb', after: ":exception\n" do <<-'CODE'
|
839
|
+
|
840
|
+
rescue_from Pundit::NotAuthorizedError, with: :account_not_authorized
|
841
|
+
CODE
|
842
|
+
end
|
843
|
+
|
844
|
+
inject_into_file 'app/controllers/application_controller.rb', after: " #end\n" do <<-'CODE'
|
845
|
+
|
846
|
+
def account_not_authorized
|
847
|
+
redirect_to request.headers['Referer'] || root_path, flash: { error: I18n.t('authorization.error') }
|
848
|
+
end
|
849
|
+
CODE
|
850
|
+
end
|
851
|
+
|
852
|
+
git add: '.'
|
853
|
+
git commit: "-m 'Add pundit logic to the application controller'"
|