kowl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +7 -0
- data/README.md +383 -0
- data/bin/console +14 -0
- data/bin/kowl +106 -0
- data/bin/setup +13 -0
- data/lib/kowl/actions.rb +240 -0
- data/lib/kowl/docker.rb +447 -0
- data/lib/kowl/generators/README.md +5 -0
- data/lib/kowl/generators/action_generator.rb +113 -0
- data/lib/kowl/generators/admin_generator.rb +114 -0
- data/lib/kowl/generators/assets_generator.rb +188 -0
- data/lib/kowl/generators/base.rb +40 -0
- data/lib/kowl/generators/circleci_generator.rb +11 -0
- data/lib/kowl/generators/config_generator.rb +180 -0
- data/lib/kowl/generators/controller_generator.rb +64 -0
- data/lib/kowl/generators/database_generator.rb +42 -0
- data/lib/kowl/generators/decorators_generator.rb +16 -0
- data/lib/kowl/generators/docker_generator.rb +40 -0
- data/lib/kowl/generators/dotfiles_generator.rb +73 -0
- data/lib/kowl/generators/libs_generator.rb +19 -0
- data/lib/kowl/generators/mailer_generator.rb +58 -0
- data/lib/kowl/generators/misc_generator.rb +20 -0
- data/lib/kowl/generators/overrides/app_base.rb +15 -0
- data/lib/kowl/generators/overrides/app_builder.rb +58 -0
- data/lib/kowl/generators/overrides/app_generator.rb +249 -0
- data/lib/kowl/generators/pages_generator.rb +46 -0
- data/lib/kowl/generators/routes_generator.rb +20 -0
- data/lib/kowl/generators/sidekiq_generator.rb +31 -0
- data/lib/kowl/generators/staging_generator.rb +14 -0
- data/lib/kowl/generators/test_generator.rb +42 -0
- data/lib/kowl/generators/text_files_generator.rb +41 -0
- data/lib/kowl/generators/users_and_auth_generator.rb +143 -0
- data/lib/kowl/generators/uuid_generator.rb +39 -0
- data/lib/kowl/generators/views_and_helpers_generator.rb +104 -0
- data/lib/kowl/geodb.rb +96 -0
- data/lib/kowl/helpers.rb +139 -0
- data/lib/kowl/templates/Gemfile.erb.tt +253 -0
- data/lib/kowl/templates/README.md.erb +33 -0
- data/lib/kowl/templates/app/assets/javascripts/semantic.js.tt +26 -0
- data/lib/kowl/templates/app/assets/stylesheets/administrate/application.scss +44 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/_custom_styling.scss +38 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/application-mailer.scss +1 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/application.scss +14 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_alerts.scss +7 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_errors.scss +28 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_navbar.scss +17 -0
- data/lib/kowl/templates/app/assets/stylesheets/bootstrap/variables.scss +6 -0
- data/lib/kowl/templates/app/assets/stylesheets/semantic/_custom_styling.scss +20 -0
- data/lib/kowl/templates/app/assets/stylesheets/semantic/application.scss +24 -0
- data/lib/kowl/templates/app/controllers/admin/application_controller.rb +29 -0
- data/lib/kowl/templates/app/controllers/admin/login_activities_controller.rb +29 -0
- data/lib/kowl/templates/app/controllers/admin/users_controller.rb +37 -0
- data/lib/kowl/templates/app/controllers/concerns/auth/authentication.rb +18 -0
- data/lib/kowl/templates/app/controllers/concerns/auth/authorization.rb +20 -0
- data/lib/kowl/templates/app/controllers/concerns/auth/error_handlers.rb +27 -0
- data/lib/kowl/templates/app/controllers/concerns/noauth/error_handlers.rb +25 -0
- data/lib/kowl/templates/app/controllers/users_controller.rb +17 -0
- data/lib/kowl/templates/app/dashboards/login_activity_dashboard.rb.tt +59 -0
- data/lib/kowl/templates/app/dashboards/rich_text_body_dashboard.rb.tt +17 -0
- data/lib/kowl/templates/app/dashboards/user_dashboard.rb.tt +60 -0
- data/lib/kowl/templates/app/fields/gravatar_field.rb +10 -0
- data/lib/kowl/templates/app/fields/rich_text_area_field.rb +8 -0
- data/lib/kowl/templates/app/inputs/rich_text_area_input.rb +11 -0
- data/lib/kowl/templates/app/javascript/administrate/components/date_time_picker.js.tt +32 -0
- data/lib/kowl/templates/app/javascript/administrate/components/table.js.tt +49 -0
- data/lib/kowl/templates/app/javascript/administrate/index.js +3 -0
- data/lib/kowl/templates/app/javascript/packs/administrate.js.tt +21 -0
- data/lib/kowl/templates/app/javascript/packs/semantic.js +11 -0
- data/lib/kowl/templates/app/mailers/application_mailer.rb +7 -0
- data/lib/kowl/templates/app/mailers/devise_mailer.rb +5 -0
- data/lib/kowl/templates/app/models/login_activity.rb.tt +29 -0
- data/lib/kowl/templates/app/models/user.rb.tt +72 -0
- data/lib/kowl/templates/app/policies/application_policy.rb +38 -0
- data/lib/kowl/templates/app/policies/login_activity_policy.rb +35 -0
- data/lib/kowl/templates/app/policies/user_policy.rb +43 -0
- data/lib/kowl/templates/app/views/admin/templates/navigation.erb.tt +23 -0
- data/lib/kowl/templates/app/views/admin/views/application/_javascript.html.erb +21 -0
- data/lib/kowl/templates/app/views/admin/views/users/_collection.html.erb +102 -0
- data/lib/kowl/templates/app/views/admin/views/users/_form.html.erb +46 -0
- data/lib/kowl/templates/app/views/admin/views/users/edit.html.erb +36 -0
- data/lib/kowl/templates/app/views/admin/views/users/index.html.erb +66 -0
- data/lib/kowl/templates/app/views/fields/gravatar_field/_form.html.erb +6 -0
- data/lib/kowl/templates/app/views/fields/gravatar_field/_index.html.erb +1 -0
- data/lib/kowl/templates/app/views/fields/gravatar_field/_show.html.erb +1 -0
- data/lib/kowl/templates/app/views/fields/rich_text_area_field/_form.html.erb +6 -0
- data/lib/kowl/templates/app/views/fields/rich_text_area_field/_index.html.erb +1 -0
- data/lib/kowl/templates/app/views/fields/rich_text_area_field/_show.html.erb +1 -0
- data/lib/kowl/templates/app/views/layouts/admin.html.erb.tt +47 -0
- data/lib/kowl/templates/app/views/layouts/devise_mailer.html.erb +14 -0
- data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.erb +18 -0
- data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.haml +17 -0
- data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.slim +17 -0
- data/lib/kowl/templates/app/views/pages/welcome/default.html.erb +0 -0
- data/lib/kowl/templates/app/views/pages/welcome/default.html.haml +0 -0
- data/lib/kowl/templates/app/views/pages/welcome/default.html.slim +0 -0
- data/lib/kowl/templates/app/views/pages/welcome/semantic.html.erb +20 -0
- data/lib/kowl/templates/app/views/pages/welcome/semantic.html.haml +17 -0
- data/lib/kowl/templates/app/views/pages/welcome/semantic.html.slim +17 -0
- data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.erb.tt +5 -0
- data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.haml.tt +3 -0
- data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.slim.tt +3 -0
- data/lib/kowl/templates/app/views/shared/footer/semantic.html.erb.tt +7 -0
- data/lib/kowl/templates/app/views/shared/footer/semantic.html.haml.tt +5 -0
- data/lib/kowl/templates/app/views/shared/footer/semantic.html.slim.tt +5 -0
- data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.erb.tt +51 -0
- data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.haml.tt +36 -0
- data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.slim.tt +36 -0
- data/lib/kowl/templates/app/views/shared/navigation/semantic.html.erb.tt +48 -0
- data/lib/kowl/templates/app/views/shared/navigation/semantic.html.haml.tt +36 -0
- data/lib/kowl/templates/app/views/shared/navigation/semantic.html.slim.tt +36 -0
- data/lib/kowl/templates/app/workers/scheduler/pghero_scheduler.rb +11 -0
- data/lib/kowl/templates/config/autoprefixer.yml +4 -0
- data/lib/kowl/templates/config/db/mysql.yml.tt +43 -0
- data/lib/kowl/templates/config/db/oracle.yml.tt +29 -0
- data/lib/kowl/templates/config/db/postgresql.yml.tt +37 -0
- data/lib/kowl/templates/config/db/sqlite3.yml.tt +20 -0
- data/lib/kowl/templates/config/db/sqlserver.yml.tt +28 -0
- data/lib/kowl/templates/config/initializers/administrate.rb.tt +9 -0
- data/lib/kowl/templates/config/initializers/bullet.rb +21 -0
- data/lib/kowl/templates/config/initializers/devise-security.rb +44 -0
- data/lib/kowl/templates/config/initializers/devise_argon2.rb +29 -0
- data/lib/kowl/templates/config/initializers/faker.rb +6 -0
- data/lib/kowl/templates/config/initializers/generators.rb.tt +31 -0
- data/lib/kowl/templates/config/initializers/geocoder.rb +10 -0
- data/lib/kowl/templates/config/initializers/letter_opener.rb +13 -0
- data/lib/kowl/templates/config/initializers/lockbox.rb +11 -0
- data/lib/kowl/templates/config/initializers/logging.rb +6 -0
- data/lib/kowl/templates/config/initializers/lograge.rb +7 -0
- data/lib/kowl/templates/config/initializers/logstop.rb +4 -0
- data/lib/kowl/templates/config/initializers/middleware.rb +9 -0
- data/lib/kowl/templates/config/initializers/oj.rb +7 -0
- data/lib/kowl/templates/config/initializers/pagy.rb.tt +16 -0
- data/lib/kowl/templates/config/initializers/postmark.rb +8 -0
- data/lib/kowl/templates/config/initializers/rack_attack.rb.tt +71 -0
- data/lib/kowl/templates/config/initializers/sass.rb +5 -0
- data/lib/kowl/templates/config/initializers/sidekiq.rb +11 -0
- data/lib/kowl/templates/config/initializers/simpleform/semantic.rb +225 -0
- data/lib/kowl/templates/config/initializers/slim.rb +6 -0
- data/lib/kowl/templates/config/initializers/sparkpost.rb +13 -0
- data/lib/kowl/templates/config/routes.rb.tt +28 -0
- data/lib/kowl/templates/config/sidekiq.yml.tt +17 -0
- data/lib/kowl/templates/db/migrations/create_action_text_tables.action_text.rb.tt +16 -0
- data/lib/kowl/templates/db/migrations/create_active_storage_tables.active_storage.rb.tt +29 -0
- data/lib/kowl/templates/db/migrations/devise.rb.tt +59 -0
- data/lib/kowl/templates/db/migrations/login_activities.rb.tt +41 -0
- data/lib/kowl/templates/db/seeds.rb.tt +14 -0
- data/lib/kowl/templates/docker/Dockerfile.alpine.tt +92 -0
- data/lib/kowl/templates/docker/Dockerfile.debian.tt +133 -0
- data/lib/kowl/templates/docker/docker-compose.yml.tt +55 -0
- data/lib/kowl/templates/docker/mysql/Dockerfile.tt +15 -0
- data/lib/kowl/templates/dotfiles/Aptfile.tt +34 -0
- data/lib/kowl/templates/dotfiles/Brewfile.tt +49 -0
- data/lib/kowl/templates/dotfiles/Procfile.tt +12 -0
- data/lib/kowl/templates/dotfiles/codeclimate.yml +76 -0
- data/lib/kowl/templates/dotfiles/coffeelint.json +10 -0
- data/lib/kowl/templates/dotfiles/coffeelintignore +15 -0
- data/lib/kowl/templates/dotfiles/dockerignore +23 -0
- data/lib/kowl/templates/dotfiles/editorconfig +13 -0
- data/lib/kowl/templates/dotfiles/env.tt +58 -0
- data/lib/kowl/templates/dotfiles/erb-lint.yml +10 -0
- data/lib/kowl/templates/dotfiles/erdconfig.tt +24 -0
- data/lib/kowl/templates/dotfiles/eslintignore +20 -0
- data/lib/kowl/templates/dotfiles/eslintrc.js +31 -0
- data/lib/kowl/templates/dotfiles/fasterer.yml +14 -0
- data/lib/kowl/templates/dotfiles/foreman +1 -0
- data/lib/kowl/templates/dotfiles/gitattributes +15 -0
- data/lib/kowl/templates/dotfiles/gitignore +69 -0
- data/lib/kowl/templates/dotfiles/haml-lint.yml +23 -0
- data/lib/kowl/templates/dotfiles/jsbeautifyrc +15 -0
- data/lib/kowl/templates/dotfiles/jshintrc +3 -0
- data/lib/kowl/templates/dotfiles/mailmap +3 -0
- data/lib/kowl/templates/dotfiles/nvmrc +1 -0
- data/lib/kowl/templates/dotfiles/prettierignore +21 -0
- data/lib/kowl/templates/dotfiles/prettierrc.js +62 -0
- data/lib/kowl/templates/dotfiles/pryrc +7 -0
- data/lib/kowl/templates/dotfiles/rspec +3 -0
- data/lib/kowl/templates/dotfiles/rubocop.yml.tt +78 -0
- data/lib/kowl/templates/dotfiles/scss-lint.yml +132 -0
- data/lib/kowl/templates/dotfiles/simplecov +19 -0
- data/lib/kowl/templates/dotfiles/slim-lint.yml +23 -0
- data/lib/kowl/templates/dotfiles/slugignore +10 -0
- data/lib/kowl/templates/dotfiles/yamllint +7 -0
- data/lib/kowl/templates/dotfiles/yarnclean +46 -0
- data/lib/kowl/templates/lib/tasks/stats.rake +42 -0
- data/lib/kowl/templates/tests/factories/README.md +0 -0
- data/lib/kowl/templates/tests/factories/login_activity.rb +11 -0
- data/lib/kowl/templates/tests/factories/user.rb +11 -0
- data/lib/kowl/templates/tests/minitest/README.md +3 -0
- data/lib/kowl/templates/tests/minitest/application_system_test_case.rb +7 -0
- data/lib/kowl/templates/tests/minitest/controllers/pages_controller_test.rb +10 -0
- data/lib/kowl/templates/tests/minitest/models/login_activity_test.rb +8 -0
- data/lib/kowl/templates/tests/minitest/models/user_test.rb +15 -0
- data/lib/kowl/templates/tests/minitest/policies/login_activity_policy_test.rb +7 -0
- data/lib/kowl/templates/tests/minitest/policies/user_policy_test.rb +7 -0
- data/lib/kowl/templates/tests/minitest/support/capybara.rb +38 -0
- data/lib/kowl/templates/tests/minitest/support/database_cleaner.rb +20 -0
- data/lib/kowl/templates/tests/minitest/support/database_cleaner_support.rb +15 -0
- data/lib/kowl/templates/tests/minitest/support/deferred_garbage_collection.rb +21 -0
- data/lib/kowl/templates/tests/minitest/support/devise.rb +16 -0
- data/lib/kowl/templates/tests/minitest/support/factories.rb +6 -0
- data/lib/kowl/templates/tests/minitest/support/formulaic.rb +8 -0
- data/lib/kowl/templates/tests/minitest/support/helpers/devise_helper.rb +57 -0
- data/lib/kowl/templates/tests/minitest/support/papertrail.rb +17 -0
- data/lib/kowl/templates/tests/minitest/support/pundit.rb +0 -0
- data/lib/kowl/templates/tests/minitest/support/shoulda.rb +11 -0
- data/lib/kowl/templates/tests/minitest/support/simplecov.rb +8 -0
- data/lib/kowl/templates/tests/minitest/test_helper.rb +17 -0
- data/lib/kowl/templates/tests/rspec/README.md +9 -0
- data/lib/kowl/templates/tests/rspec/controllers/admin/application_controller_spec.rb +12 -0
- data/lib/kowl/templates/tests/rspec/controllers/admin/users_controller_spec.rb +14 -0
- data/lib/kowl/templates/tests/rspec/controllers/pages_controller_spec.rb +10 -0
- data/lib/kowl/templates/tests/rspec/features/README.md +15 -0
- data/lib/kowl/templates/tests/rspec/features/visitor_sign_up_spec.rb +25 -0
- data/lib/kowl/templates/tests/rspec/helpers/application_helper_spec.rb +7 -0
- data/lib/kowl/templates/tests/rspec/helpers/pages_helper_spec.rb +15 -0
- data/lib/kowl/templates/tests/rspec/models/login_activity_spec.rb +11 -0
- data/lib/kowl/templates/tests/rspec/models/user_spec.rb +21 -0
- data/lib/kowl/templates/tests/rspec/policies/login_activity_policy_spec.rb +59 -0
- data/lib/kowl/templates/tests/rspec/policies/user_policy_spec.rb +56 -0
- data/lib/kowl/templates/tests/rspec/rails_helper.rb +72 -0
- data/lib/kowl/templates/tests/rspec/requests/pages_spec.rb +11 -0
- data/lib/kowl/templates/tests/rspec/spec_helper.rb +96 -0
- data/lib/kowl/templates/tests/rspec/support/bullet.rb +17 -0
- data/lib/kowl/templates/tests/rspec/support/capybara.rb +37 -0
- data/lib/kowl/templates/tests/rspec/support/controller_testing.rb +10 -0
- data/lib/kowl/templates/tests/rspec/support/database_cleaner.rb +55 -0
- data/lib/kowl/templates/tests/rspec/support/deferred_garbage_collection.rb +32 -0
- data/lib/kowl/templates/tests/rspec/support/devise.rb +21 -0
- data/lib/kowl/templates/tests/rspec/support/factories.rb +5 -0
- data/lib/kowl/templates/tests/rspec/support/formulaic.rb +8 -0
- data/lib/kowl/templates/tests/rspec/support/helpers/devise_helpers.rb +56 -0
- data/lib/kowl/templates/tests/rspec/support/papertrail.rb +5 -0
- data/lib/kowl/templates/tests/rspec/support/pi_ci.rb +6 -0
- data/lib/kowl/templates/tests/rspec/support/pundit.rb +6 -0
- data/lib/kowl/templates/tests/rspec/support/shoulda.rb +10 -0
- data/lib/kowl/templates/tests/rspec/support/sidekiq.rb +10 -0
- data/lib/kowl/templates/tests/rspec/support/simplecov.rb +7 -0
- data/lib/kowl/templates/tests/rspec/support/warden.rb +8 -0
- data/lib/kowl/templates/text_files/AUTHORS.md +4 -0
- data/lib/kowl/templates/text_files/CHANGELOG.md.tt +12 -0
- data/lib/kowl/templates/text_files/CODE_OF_CONDUCT.md +76 -0
- data/lib/kowl/templates/text_files/TODO.md +7 -0
- data/lib/kowl/templates/text_files/VERSION +1 -0
- data/lib/kowl/templates/text_files/humans.txt.tt +15 -0
- data/lib/kowl/templates/text_files/robots.txt.tt +6 -0
- data/lib/kowl/templates/text_files/security.txt +6 -0
- data/lib/kowl/version.rb +9 -0
- data/lib/kowl.rb +18 -0
- metadata +404 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Use argon instead of bcrypt for devise
|
4
|
+
# => https://ankane.org/devise-argon2
|
5
|
+
if defined?(Devise)
|
6
|
+
module Argon2Encryptor
|
7
|
+
def digest(klass, password)
|
8
|
+
if klass.pepper.present?
|
9
|
+
password = "#{password}#{klass.pepper}"
|
10
|
+
end
|
11
|
+
::Argon2::Password.create(password)
|
12
|
+
end
|
13
|
+
|
14
|
+
def compare(klass, hashed_password, password)
|
15
|
+
return false if hashed_password.blank?
|
16
|
+
|
17
|
+
if hashed_password.start_with?('$argon2')
|
18
|
+
if klass.pepper.present?
|
19
|
+
password = "#{password}#{klass.pepper}"
|
20
|
+
end
|
21
|
+
::Argon2::Password.verify_password(password, hashed_password)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Devise::Encryptor.singleton_class.prepend(Argon2Encryptor)
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Rails.application.config.generators do |g|
|
4
|
+
g.assets false
|
5
|
+
g.javascripts false
|
6
|
+
<%- unless options[:framework].blank? || options[:framework] == 'none' -%>
|
7
|
+
g.stylesheets false
|
8
|
+
<%- end -%>
|
9
|
+
g.jbuilder false
|
10
|
+
# g.helper false
|
11
|
+
<%- if options[:simpleform] -%>
|
12
|
+
g.form_framework :simple_form
|
13
|
+
<%- end -%>
|
14
|
+
<%- if options[:template_engine] != 'erb' -%>
|
15
|
+
g.template_engine :<%= options[:template_engine] %>
|
16
|
+
<%- end -%>
|
17
|
+
<%- if options[:database] == 'postgresql' && options[:uuid] -%>
|
18
|
+
g.orm :active_record, primary_key_type: :uuid
|
19
|
+
<%- end -%>
|
20
|
+
|
21
|
+
<%- unless options[:test_engine].blank? || options[:skip_tests] -%>
|
22
|
+
# Test generators
|
23
|
+
g.fixture_replacement :factory_bot, dir: '<%= (options[:test_engine] == 'rspec' ? 'spec' : 'test') -%>/factories'
|
24
|
+
<%- if options[:test_engine] == 'minitest' -%>
|
25
|
+
g.test_framework :test_unit, fixture: true
|
26
|
+
<%- elsif options[:test_engine] == 'rspec' -%>
|
27
|
+
g.integration_tool :rspec
|
28
|
+
g.test_framework :rspec, fixture: false
|
29
|
+
<%- end -%>
|
30
|
+
<%- end -%>
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(LetterOpener)
|
4
|
+
LetterOpener.configure do |config|
|
5
|
+
# To overrider the location for message storage.
|
6
|
+
# Default value is <tt>tmp/letter_opener</tt>
|
7
|
+
config.location = Rails.root.join('tmp', 'letter_opener')
|
8
|
+
|
9
|
+
# To render only the message body, without any metadata or extra containers or styling.
|
10
|
+
# Default value is <tt>:default</tt> that renders styled message with showing useful metadata.
|
11
|
+
config.message_template = :light
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(Lockbox)
|
4
|
+
Lockbox.master_key = ENV['LOCKBOX_MASTER_KEY']
|
5
|
+
BlindIndex.master_key = Lockbox.master_key
|
6
|
+
|
7
|
+
# Set all default encryptions to use xsalsa20 (requires libsodium)
|
8
|
+
# https://github.com/ankane/lockbox#xsalsa20
|
9
|
+
# https://github.com/ankane/lockbox#padding
|
10
|
+
Lockbox.default_options = { algorithm: 'xsalsa20', padding: true }
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(Pagy)
|
4
|
+
<%- if options[:framework] == 'bootstrap' -%>
|
5
|
+
require 'pagy/extras/bootstrap'
|
6
|
+
<%- elsif options[:framework] == 'semantic' -%>
|
7
|
+
require 'pagy/extras/semantic'
|
8
|
+
<%- end -%>
|
9
|
+
require 'pagy/extras/trim' # No need for page=1
|
10
|
+
require 'pagy/extras/overflow' # prevent user form requesting a page from the last resulting page
|
11
|
+
# require 'pagy/extras/countless' # Used to avoid issuing additional count queries when doing pagination
|
12
|
+
|
13
|
+
Pagy::VARS[:overflow] = :last_page
|
14
|
+
# Set default number of items per page as 25
|
15
|
+
Pagy::VARS[:items] = 25
|
16
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# https://github.com/kickstarter/rack-attack
|
4
|
+
# https://ankane.org/hardening-devise#rate-limit-login-attempts
|
5
|
+
# https://www.diycode.cc/projects/kickstarter/rack-attack
|
6
|
+
# https://blog.bigbinary.com/2018/05/15/how-to-mitigate-ddos-using-rack-attack.html
|
7
|
+
# https://redpanthers.co/rack-attack-secure-you-rails-app-for-the-real-world/
|
8
|
+
# https://github.com/studentinsights/studentinsights/blob/master/config/initializers/rack_attack.rb
|
9
|
+
if defined?(Rack::Attack)
|
10
|
+
class Rack::Attack
|
11
|
+
# https://github.com/kickstarter/rack-attack#cache-store-configuration
|
12
|
+
# CacheStore is only used for throttling, allow2ban and fail2ban filtering (blocklisting and safelisting not included)
|
13
|
+
<%- if options[:skip_sidekiq] -%>
|
14
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
15
|
+
<%- else -%>
|
16
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new
|
17
|
+
<%- end -%>
|
18
|
+
|
19
|
+
if Rails.env.production?
|
20
|
+
# Limit a client to have a max of 40 requests a minute
|
21
|
+
throttle('req/ip', limit: 40, period: 1.minute) do |req|
|
22
|
+
req.ip if req.path == '/'
|
23
|
+
end
|
24
|
+
|
25
|
+
<%- unless options[:noauth] -%>
|
26
|
+
# Used to throttle requests on failed login attempts
|
27
|
+
throttle('logins/ip', limit: 20, period: 1.hour) do |req|
|
28
|
+
req.ip if req.post? && req.path.start_with?('/users/sign_in')
|
29
|
+
end
|
30
|
+
|
31
|
+
# Devise based throttling
|
32
|
+
throttle('users/sign_up', limit: 3, period: 15.minutes) do |req|
|
33
|
+
# Using “vanilla” devise inside a User model
|
34
|
+
req.ip if req.path == '/users' && req.post?
|
35
|
+
end
|
36
|
+
|
37
|
+
throttle('users/sign_in', limit: 7, period: 15.minutes) do |req|
|
38
|
+
# Using “vanilla” devise inside a User model
|
39
|
+
req.ip if req.path == '/users/sign_in' && req.post?
|
40
|
+
end
|
41
|
+
<%- end -%>
|
42
|
+
end
|
43
|
+
|
44
|
+
# Make localhost safe to receive a large number of requests from the application
|
45
|
+
safelist('allow from localhost') do |req|
|
46
|
+
'127.0.0.1' == req.ip || '::1' == req.ip
|
47
|
+
end
|
48
|
+
|
49
|
+
Rack::Attack.blocklisted_response = lambda do |env|
|
50
|
+
# Using 503 because it may make attacker think that they have successfully
|
51
|
+
# DOSed the site. Rack::Attack returns 403 for blocklists by default
|
52
|
+
[ 503, {}, ['Blocked']]
|
53
|
+
end
|
54
|
+
|
55
|
+
Rack::Attack.throttled_response = lambda do |env|
|
56
|
+
# NB: you have access to the name and other data about the matched throttle
|
57
|
+
# env['rack.attack.matched'],
|
58
|
+
# env['rack.attack.match_type'],
|
59
|
+
# env['rack.attack.match_data'],
|
60
|
+
# env['rack.attack.match_discriminator']
|
61
|
+
|
62
|
+
# Using 503 because it may make attacker think that they have successfully
|
63
|
+
# DOSed the site. Rack::Attack returns 429 for throttling by default
|
64
|
+
[ 503, {}, ["Server Error\n"]]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req|
|
69
|
+
# puts "Throttled #{req.env['rack.attack.match_discriminator']}"
|
70
|
+
# end
|
71
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sidekiq'
|
4
|
+
# https://github.com/mperham/sidekiq/issues/3535
|
5
|
+
|
6
|
+
if defined?(Sidekiq)
|
7
|
+
Sidekiq.configure_server do |config|
|
8
|
+
# use hiredis for C based redis client connection
|
9
|
+
config.redis = { driver: :hiredis, url: ENV.fetch('REDIS_URL'){ 'redis://localhost:6379/0' } }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
## src: https://pranavsingh.me/semantic-ui-simple-form-wrapper/
|
4
|
+
# Use this setup block to configure all options available in SimpleForm.
|
5
|
+
SimpleForm.setup do |config|
|
6
|
+
# Wrappers are used by the form builder to generate a
|
7
|
+
# complete input. You can remove any component from the
|
8
|
+
# wrapper, change the order or even add your own to the
|
9
|
+
# stack. The options given below are used to wrap the
|
10
|
+
# whole input.
|
11
|
+
config.wrappers :default, class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|
|
12
|
+
## Extensions enabled by default
|
13
|
+
# Any of these extensions can be disabled for a
|
14
|
+
# given input by passing: `f.input EXTENSION_NAME => false`.
|
15
|
+
# You can make any of these extensions optional by
|
16
|
+
# renaming `b.use` to `b.optional`.
|
17
|
+
|
18
|
+
# Determines whether to use HTML5 (:email, :url, ...)
|
19
|
+
# and required attributes
|
20
|
+
b.use :html5
|
21
|
+
|
22
|
+
# Calculates placeholders automatically from I18n
|
23
|
+
# You can also pass a string as f.input placeholder: "Placeholder"
|
24
|
+
b.use :placeholder
|
25
|
+
|
26
|
+
## Optional extensions
|
27
|
+
# They are disabled unless you pass `f.input EXTENSION_NAME => true`
|
28
|
+
# to the input. If so, they will retrieve the values from the model
|
29
|
+
# if any exists. If you want to enable any of those
|
30
|
+
# extensions by default, you can change `b.optional` to `b.use`.
|
31
|
+
|
32
|
+
# Calculates maxlength from length validations for string inputs
|
33
|
+
# and/or database column lengths
|
34
|
+
b.optional :maxlength
|
35
|
+
|
36
|
+
# Calculate minlength from length validations for string inputs
|
37
|
+
b.optional :minlength
|
38
|
+
|
39
|
+
# Calculates pattern from format validations for string inputs
|
40
|
+
b.optional :pattern
|
41
|
+
|
42
|
+
# Calculates min and max from length validations for numeric inputs
|
43
|
+
b.optional :min_max
|
44
|
+
|
45
|
+
# Calculates readonly automatically from readonly attributes
|
46
|
+
b.optional :readonly
|
47
|
+
|
48
|
+
## Inputs
|
49
|
+
b.use :label_input
|
50
|
+
b.use :hint, wrap_with: { tag: :span, class: :hint }
|
51
|
+
b.use :error, wrap_with: { tag: :span, class: :error }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Custom Semantic Wrapper
|
55
|
+
# Values are similar to the default wrapper above, with different classes
|
56
|
+
config.wrappers :semantic, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
57
|
+
b.use :html5
|
58
|
+
b.use :placeholder
|
59
|
+
b.optional :maxlength
|
60
|
+
b.optional :pattern
|
61
|
+
b.optional :min_max
|
62
|
+
b.use :label_input
|
63
|
+
b.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
64
|
+
b.use :error, wrap_with: { tag: 'div', class: 'ui red pointing above label error' }
|
65
|
+
end
|
66
|
+
|
67
|
+
config.wrappers :ui_checkbox, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
68
|
+
b.use :html5
|
69
|
+
b.wrapper tag: 'div', class: 'ui checkbox' do |input|
|
70
|
+
input.use :label_input
|
71
|
+
input.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
config.wrappers :ui_slider_checkbox, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
76
|
+
b.use :html5
|
77
|
+
b.wrapper tag: 'div', class: 'ui slider checkbox' do |input|
|
78
|
+
input.use :label_input
|
79
|
+
input.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
config.wrappers :ui_toggle_checkbox, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
84
|
+
b.use :html5
|
85
|
+
b.wrapper tag: 'div', class: 'ui toggle checkbox' do |input|
|
86
|
+
input.use :label_input
|
87
|
+
input.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
config.wrappers :ui_left_labled_input, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
92
|
+
b.use :html5
|
93
|
+
b.use :label
|
94
|
+
|
95
|
+
b.wrapper tag: 'div', class: 'ui left labeled input' do |input|
|
96
|
+
input.use :input
|
97
|
+
input.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
config.wrappers :ui_right_labled_input, tag: 'div', class: 'field', error_class: 'error', hint_class: 'with_hint' do |b|
|
102
|
+
b.use :html5
|
103
|
+
b.use :label
|
104
|
+
|
105
|
+
b.wrapper tag: 'div', class: 'ui right labeled input' do |input|
|
106
|
+
input.use :input
|
107
|
+
input.use :hint, wrap_with: { tag: 'div', class: 'hint' }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# The default wrapper to be used by the FormBuilder.
|
112
|
+
# config.default_wrapper = :default
|
113
|
+
config.default_wrapper = :semantic
|
114
|
+
|
115
|
+
# Define the way to render check boxes / radio buttons with labels.
|
116
|
+
# Defaults to :nested for bootstrap config.
|
117
|
+
# inline: input + label
|
118
|
+
# nested: label > input
|
119
|
+
config.boolean_style = :inline
|
120
|
+
|
121
|
+
# Default class for buttons
|
122
|
+
config.button_class = 'ui primary submit button'
|
123
|
+
|
124
|
+
# Method used to tidy up errors. Specify any Rails Array method.
|
125
|
+
# :first lists the first message for each field.
|
126
|
+
# Use :to_sentence to list all errors for each field.
|
127
|
+
config.error_method = :first
|
128
|
+
|
129
|
+
# Default tag used for error notification helper.
|
130
|
+
config.error_notification_tag = :div
|
131
|
+
|
132
|
+
# CSS class to add for error notification helper.
|
133
|
+
config.error_notification_class = 'alert alert-error'
|
134
|
+
|
135
|
+
# ID to add for error notification helper.
|
136
|
+
# config.error_notification_id = nil
|
137
|
+
|
138
|
+
# Series of attempts to detect a default label method for collection.
|
139
|
+
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
|
140
|
+
|
141
|
+
# Series of attempts to detect a default value method for collection.
|
142
|
+
# config.collection_value_methods = [ :id, :to_s ]
|
143
|
+
|
144
|
+
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
|
145
|
+
# config.collection_wrapper_tag = :div
|
146
|
+
|
147
|
+
# You can define the class to use on all collection wrappers. Defaulting to none.
|
148
|
+
# config.collection_wrapper_class = 'field'
|
149
|
+
|
150
|
+
# You can wrap each item in a collection of radio/check boxes with a tag,
|
151
|
+
# defaulting to :span. Please note that when using :boolean_style = :nested,
|
152
|
+
# SimpleForm will force this option to be a label.
|
153
|
+
config.item_wrapper_tag = :div
|
154
|
+
|
155
|
+
# You can define a class to use in all item wrappers. Defaulting to none.
|
156
|
+
config.item_wrapper_class = 'ui checkbox'
|
157
|
+
|
158
|
+
# How the label text should be generated altogether with the required text.
|
159
|
+
# config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
|
160
|
+
config.label_text = lambda { |label, required, explicit_label| "#{label}" }
|
161
|
+
# Semantic UI has its own astrick
|
162
|
+
|
163
|
+
# You can define the class to use on all labels. Default is nil.
|
164
|
+
# config.label_class = nil
|
165
|
+
|
166
|
+
# You can define the class to use on all forms. Default is simple_form.
|
167
|
+
config.default_form_class = 'ui form'
|
168
|
+
|
169
|
+
# You can define which elements should obtain additional classes
|
170
|
+
# config.generate_additional_classes_for = [:wrapper, :label, :input]
|
171
|
+
|
172
|
+
# Whether attributes are required by default (or not). Default is true.
|
173
|
+
# config.required_by_default = true
|
174
|
+
|
175
|
+
# Tell browsers whether to use the native HTML5 validations (novalidate form option).
|
176
|
+
# These validations are enabled in SimpleForm's internal config but disabled by default
|
177
|
+
# in this configuration, which is recommended due to some quirks from different browsers.
|
178
|
+
# To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
|
179
|
+
# change this configuration to true.
|
180
|
+
config.browser_validations = false
|
181
|
+
|
182
|
+
# Collection of methods to detect if a file type was given.
|
183
|
+
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
|
184
|
+
|
185
|
+
# Custom mappings for input types. This should be a hash containing a regexps
|
186
|
+
# to match as key, and the input type that will be used when the field name
|
187
|
+
# matches the regexp as value.
|
188
|
+
# config.input_mappings = { /count/ => :integer }
|
189
|
+
|
190
|
+
# Custom wrappers for input types. This should be a hash containing an input
|
191
|
+
# type as key and the wrapper that will be used for all inputs with specified type.
|
192
|
+
# config.wrapper_mappings = { string: :prepend }
|
193
|
+
|
194
|
+
# Namespaces where SimpleForm should look for custom input classes that
|
195
|
+
# override default inputs.
|
196
|
+
# config.custom_inputs_namespaces << "CustomInputs"
|
197
|
+
|
198
|
+
# Default priority for time_zone inputs.
|
199
|
+
# config.time_zone_priority = nil
|
200
|
+
|
201
|
+
# Default priority for country inputs.
|
202
|
+
# config.country_priority = nil
|
203
|
+
|
204
|
+
# When false, do not use translations for labels.
|
205
|
+
# config.translate_labels = true
|
206
|
+
|
207
|
+
# Automatically discover new inputs in Rails' autoload path.
|
208
|
+
# config.inputs_discovery = true
|
209
|
+
|
210
|
+
# Cache SimpleForm inputs discovery
|
211
|
+
# config.cache_discovery = !Rails.env.development?
|
212
|
+
|
213
|
+
# Default class for inputs
|
214
|
+
# config.input_class = nil
|
215
|
+
|
216
|
+
# Define the default class of the input wrapper of the boolean input.
|
217
|
+
config.boolean_label_class = 'checkbox'
|
218
|
+
|
219
|
+
# Defines if the default input wrapper class should be included in radio
|
220
|
+
# collection wrappers.
|
221
|
+
# config.include_default_input_wrapper_class = true
|
222
|
+
|
223
|
+
# Defines which i18n scope will be used in Simple Form.
|
224
|
+
# config.i18n_scope = 'simple_form'
|
225
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if Rails.env.production? && defined?(SparkPostRails)
|
4
|
+
SparkPostRails.configure do |c|
|
5
|
+
c.api_key = ENV['SPARKPOST_API_KEY']
|
6
|
+
c.sandbox = false # default: false
|
7
|
+
c.track_opens = true # default: false
|
8
|
+
c.track_clicks = true # default: false
|
9
|
+
c.transactional = true # default: false
|
10
|
+
c.inline_css = true # default: false
|
11
|
+
c.html_content_only = true # default: false
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%- unless options[:skip_sidekiq] -%>
|
4
|
+
require 'sidekiq/web'
|
5
|
+
require 'sidekiq-scheduler/web'
|
6
|
+
|
7
|
+
<%- end -%>
|
8
|
+
Rails.application.routes.draw do
|
9
|
+
<%- unless options[:noauth] -%>
|
10
|
+
devise_for :users
|
11
|
+
resources :users, only: [:index] do
|
12
|
+
get :impersonate, on: :member
|
13
|
+
post :stop_impersonating, on: :collection
|
14
|
+
end
|
15
|
+
|
16
|
+
# Admin/Dashboard
|
17
|
+
namespace :admin do
|
18
|
+
resources :users
|
19
|
+
resources :login_activities
|
20
|
+
root to: 'users#index'
|
21
|
+
end
|
22
|
+
<%- end -%>
|
23
|
+
|
24
|
+
<%= add_extension_routes(options) -%>
|
25
|
+
get 'welcome', to: 'pages#welcome', as: :welcome
|
26
|
+
root to: 'pages#welcome'
|
27
|
+
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
:verbose: false
|
3
|
+
:pidfile: ./tmp/pids/sidekiq.pid
|
4
|
+
:concurrency: <%= ENV.fetch('RAILS_MAX_THREADS', 5).to_i %>
|
5
|
+
:timeout: <%= ENV.fetch('JOB_TIMEOUT', 120).to_i %>
|
6
|
+
# :max_retries: <%= ENV.fetch('JOB_RETRY_ATTEMPTS', 5).to_i %>
|
7
|
+
:queues:
|
8
|
+
- [critical, 10]
|
9
|
+
- [default, 6]
|
10
|
+
- [mailer, 2]
|
11
|
+
- [low, 1]
|
12
|
+
<%- if options[:database] == 'postgresql' -%>
|
13
|
+
:schedule:
|
14
|
+
pghero_scheduler:
|
15
|
+
every: '5m'
|
16
|
+
class: Scheduler::PgheroScheduler
|
17
|
+
<%- end -%>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This migration comes from action_text (originally 20180528164100)
|
4
|
+
class CreateActionTextTables < ActiveRecord::Migration[6.0]
|
5
|
+
def change
|
6
|
+
create_table :action_text_rich_texts do |t|
|
7
|
+
t.string :name, null: false
|
8
|
+
t.text :body, size: :long
|
9
|
+
t.references :record, null: false, polymorphic: true, index: false
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
|
13
|
+
t.index [ :record_type, :record_id, :name ], name: 'index_action_text_rich_texts_uniqueness', unique: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This migration comes from active_storage (originally 20170806125915)
|
4
|
+
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
|
5
|
+
def change
|
6
|
+
create_table :active_storage_blobs do |t|
|
7
|
+
t.string :key, null: false
|
8
|
+
t.string :filename, null: false
|
9
|
+
t.string :content_type
|
10
|
+
t.text :metadata
|
11
|
+
t.bigint :byte_size, null: false
|
12
|
+
t.string :checksum, null: false
|
13
|
+
t.datetime :created_at, null: false
|
14
|
+
|
15
|
+
t.index [ :key ], unique: true
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :active_storage_attachments do |t|
|
19
|
+
t.string :name, null: false
|
20
|
+
t.references :record, null: false, polymorphic: true, index: false
|
21
|
+
t.references :blob, null: false
|
22
|
+
|
23
|
+
t.datetime :created_at, null: false
|
24
|
+
|
25
|
+
t.index [ :record_type, :record_id, :name, :blob_id ], name: 'index_active_storage_attachments_uniqueness', unique: true
|
26
|
+
t.foreign_key :active_storage_blobs, column: :blob_id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :users do |t|
|
6
|
+
## Database authenticatable
|
7
|
+
<%- if options[:encrypt] -%>
|
8
|
+
# https://ankane.org/securing-user-emails-lockbox
|
9
|
+
# Encrypt user data
|
10
|
+
t.string :email_ciphertext
|
11
|
+
t.string :email_bidx
|
12
|
+
<%- else -%>
|
13
|
+
t.string :email, null: false, default: ''
|
14
|
+
<%- end -%>
|
15
|
+
|
16
|
+
t.string :encrypted_password, null: false, default: ''
|
17
|
+
|
18
|
+
## Recoverable
|
19
|
+
t.string :reset_password_token
|
20
|
+
t.datetime :reset_password_sent_at
|
21
|
+
|
22
|
+
## Rememberable
|
23
|
+
t.datetime :remember_created_at
|
24
|
+
|
25
|
+
## Trackable
|
26
|
+
t.integer :sign_in_count, default: 0, null: false
|
27
|
+
t.datetime :current_sign_in_at
|
28
|
+
t.datetime :last_sign_in_at
|
29
|
+
t.string :current_sign_in_ip
|
30
|
+
t.string :last_sign_in_ip
|
31
|
+
|
32
|
+
## Confirmable
|
33
|
+
# t.string :confirmation_token
|
34
|
+
# t.datetime :confirmed_at
|
35
|
+
# t.datetime :confirmation_sent_at
|
36
|
+
# t.string :unconfirmed_email # Only if using reconfirmable
|
37
|
+
|
38
|
+
## Lockable
|
39
|
+
t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
|
40
|
+
t.string :unlock_token # Only if unlock strategy is :email or :both
|
41
|
+
t.datetime :locked_at
|
42
|
+
|
43
|
+
# User Role as an integer :enum
|
44
|
+
t.integer :role
|
45
|
+
# t.string :role
|
46
|
+
|
47
|
+
t.timestamps null: false
|
48
|
+
end
|
49
|
+
|
50
|
+
<%- if options[:encrypt] -%>
|
51
|
+
add_index :users, :email_bidx, unique: true
|
52
|
+
<%- else -%>
|
53
|
+
add_index :users, :email, unique: true
|
54
|
+
<%- end -%>
|
55
|
+
add_index :users, :reset_password_token, unique: true
|
56
|
+
# add_index :users, :confirmation_token, unique: true
|
57
|
+
add_index :users, :unlock_token, unique: true
|
58
|
+
end
|
59
|
+
end
|