kowl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +7 -0
  3. data/README.md +383 -0
  4. data/bin/console +14 -0
  5. data/bin/kowl +106 -0
  6. data/bin/setup +13 -0
  7. data/lib/kowl/actions.rb +240 -0
  8. data/lib/kowl/docker.rb +447 -0
  9. data/lib/kowl/generators/README.md +5 -0
  10. data/lib/kowl/generators/action_generator.rb +113 -0
  11. data/lib/kowl/generators/admin_generator.rb +114 -0
  12. data/lib/kowl/generators/assets_generator.rb +188 -0
  13. data/lib/kowl/generators/base.rb +40 -0
  14. data/lib/kowl/generators/circleci_generator.rb +11 -0
  15. data/lib/kowl/generators/config_generator.rb +180 -0
  16. data/lib/kowl/generators/controller_generator.rb +64 -0
  17. data/lib/kowl/generators/database_generator.rb +42 -0
  18. data/lib/kowl/generators/decorators_generator.rb +16 -0
  19. data/lib/kowl/generators/docker_generator.rb +40 -0
  20. data/lib/kowl/generators/dotfiles_generator.rb +73 -0
  21. data/lib/kowl/generators/libs_generator.rb +19 -0
  22. data/lib/kowl/generators/mailer_generator.rb +58 -0
  23. data/lib/kowl/generators/misc_generator.rb +20 -0
  24. data/lib/kowl/generators/overrides/app_base.rb +15 -0
  25. data/lib/kowl/generators/overrides/app_builder.rb +58 -0
  26. data/lib/kowl/generators/overrides/app_generator.rb +249 -0
  27. data/lib/kowl/generators/pages_generator.rb +46 -0
  28. data/lib/kowl/generators/routes_generator.rb +20 -0
  29. data/lib/kowl/generators/sidekiq_generator.rb +31 -0
  30. data/lib/kowl/generators/staging_generator.rb +14 -0
  31. data/lib/kowl/generators/test_generator.rb +42 -0
  32. data/lib/kowl/generators/text_files_generator.rb +41 -0
  33. data/lib/kowl/generators/users_and_auth_generator.rb +143 -0
  34. data/lib/kowl/generators/uuid_generator.rb +39 -0
  35. data/lib/kowl/generators/views_and_helpers_generator.rb +104 -0
  36. data/lib/kowl/geodb.rb +96 -0
  37. data/lib/kowl/helpers.rb +139 -0
  38. data/lib/kowl/templates/Gemfile.erb.tt +253 -0
  39. data/lib/kowl/templates/README.md.erb +33 -0
  40. data/lib/kowl/templates/app/assets/javascripts/semantic.js.tt +26 -0
  41. data/lib/kowl/templates/app/assets/stylesheets/administrate/application.scss +44 -0
  42. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/_custom_styling.scss +38 -0
  43. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/application-mailer.scss +1 -0
  44. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/application.scss +14 -0
  45. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_alerts.scss +7 -0
  46. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_errors.scss +28 -0
  47. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/components/_navbar.scss +17 -0
  48. data/lib/kowl/templates/app/assets/stylesheets/bootstrap/variables.scss +6 -0
  49. data/lib/kowl/templates/app/assets/stylesheets/semantic/_custom_styling.scss +20 -0
  50. data/lib/kowl/templates/app/assets/stylesheets/semantic/application.scss +24 -0
  51. data/lib/kowl/templates/app/controllers/admin/application_controller.rb +29 -0
  52. data/lib/kowl/templates/app/controllers/admin/login_activities_controller.rb +29 -0
  53. data/lib/kowl/templates/app/controllers/admin/users_controller.rb +37 -0
  54. data/lib/kowl/templates/app/controllers/concerns/auth/authentication.rb +18 -0
  55. data/lib/kowl/templates/app/controllers/concerns/auth/authorization.rb +20 -0
  56. data/lib/kowl/templates/app/controllers/concerns/auth/error_handlers.rb +27 -0
  57. data/lib/kowl/templates/app/controllers/concerns/noauth/error_handlers.rb +25 -0
  58. data/lib/kowl/templates/app/controllers/users_controller.rb +17 -0
  59. data/lib/kowl/templates/app/dashboards/login_activity_dashboard.rb.tt +59 -0
  60. data/lib/kowl/templates/app/dashboards/rich_text_body_dashboard.rb.tt +17 -0
  61. data/lib/kowl/templates/app/dashboards/user_dashboard.rb.tt +60 -0
  62. data/lib/kowl/templates/app/fields/gravatar_field.rb +10 -0
  63. data/lib/kowl/templates/app/fields/rich_text_area_field.rb +8 -0
  64. data/lib/kowl/templates/app/inputs/rich_text_area_input.rb +11 -0
  65. data/lib/kowl/templates/app/javascript/administrate/components/date_time_picker.js.tt +32 -0
  66. data/lib/kowl/templates/app/javascript/administrate/components/table.js.tt +49 -0
  67. data/lib/kowl/templates/app/javascript/administrate/index.js +3 -0
  68. data/lib/kowl/templates/app/javascript/packs/administrate.js.tt +21 -0
  69. data/lib/kowl/templates/app/javascript/packs/semantic.js +11 -0
  70. data/lib/kowl/templates/app/mailers/application_mailer.rb +7 -0
  71. data/lib/kowl/templates/app/mailers/devise_mailer.rb +5 -0
  72. data/lib/kowl/templates/app/models/login_activity.rb.tt +29 -0
  73. data/lib/kowl/templates/app/models/user.rb.tt +72 -0
  74. data/lib/kowl/templates/app/policies/application_policy.rb +38 -0
  75. data/lib/kowl/templates/app/policies/login_activity_policy.rb +35 -0
  76. data/lib/kowl/templates/app/policies/user_policy.rb +43 -0
  77. data/lib/kowl/templates/app/views/admin/templates/navigation.erb.tt +23 -0
  78. data/lib/kowl/templates/app/views/admin/views/application/_javascript.html.erb +21 -0
  79. data/lib/kowl/templates/app/views/admin/views/users/_collection.html.erb +102 -0
  80. data/lib/kowl/templates/app/views/admin/views/users/_form.html.erb +46 -0
  81. data/lib/kowl/templates/app/views/admin/views/users/edit.html.erb +36 -0
  82. data/lib/kowl/templates/app/views/admin/views/users/index.html.erb +66 -0
  83. data/lib/kowl/templates/app/views/fields/gravatar_field/_form.html.erb +6 -0
  84. data/lib/kowl/templates/app/views/fields/gravatar_field/_index.html.erb +1 -0
  85. data/lib/kowl/templates/app/views/fields/gravatar_field/_show.html.erb +1 -0
  86. data/lib/kowl/templates/app/views/fields/rich_text_area_field/_form.html.erb +6 -0
  87. data/lib/kowl/templates/app/views/fields/rich_text_area_field/_index.html.erb +1 -0
  88. data/lib/kowl/templates/app/views/fields/rich_text_area_field/_show.html.erb +1 -0
  89. data/lib/kowl/templates/app/views/layouts/admin.html.erb.tt +47 -0
  90. data/lib/kowl/templates/app/views/layouts/devise_mailer.html.erb +14 -0
  91. data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.erb +18 -0
  92. data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.haml +17 -0
  93. data/lib/kowl/templates/app/views/pages/welcome/bootstrap.html.slim +17 -0
  94. data/lib/kowl/templates/app/views/pages/welcome/default.html.erb +0 -0
  95. data/lib/kowl/templates/app/views/pages/welcome/default.html.haml +0 -0
  96. data/lib/kowl/templates/app/views/pages/welcome/default.html.slim +0 -0
  97. data/lib/kowl/templates/app/views/pages/welcome/semantic.html.erb +20 -0
  98. data/lib/kowl/templates/app/views/pages/welcome/semantic.html.haml +17 -0
  99. data/lib/kowl/templates/app/views/pages/welcome/semantic.html.slim +17 -0
  100. data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.erb.tt +5 -0
  101. data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.haml.tt +3 -0
  102. data/lib/kowl/templates/app/views/shared/footer/bootstrap.html.slim.tt +3 -0
  103. data/lib/kowl/templates/app/views/shared/footer/semantic.html.erb.tt +7 -0
  104. data/lib/kowl/templates/app/views/shared/footer/semantic.html.haml.tt +5 -0
  105. data/lib/kowl/templates/app/views/shared/footer/semantic.html.slim.tt +5 -0
  106. data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.erb.tt +51 -0
  107. data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.haml.tt +36 -0
  108. data/lib/kowl/templates/app/views/shared/navigation/bootstrap.html.slim.tt +36 -0
  109. data/lib/kowl/templates/app/views/shared/navigation/semantic.html.erb.tt +48 -0
  110. data/lib/kowl/templates/app/views/shared/navigation/semantic.html.haml.tt +36 -0
  111. data/lib/kowl/templates/app/views/shared/navigation/semantic.html.slim.tt +36 -0
  112. data/lib/kowl/templates/app/workers/scheduler/pghero_scheduler.rb +11 -0
  113. data/lib/kowl/templates/config/autoprefixer.yml +4 -0
  114. data/lib/kowl/templates/config/db/mysql.yml.tt +43 -0
  115. data/lib/kowl/templates/config/db/oracle.yml.tt +29 -0
  116. data/lib/kowl/templates/config/db/postgresql.yml.tt +37 -0
  117. data/lib/kowl/templates/config/db/sqlite3.yml.tt +20 -0
  118. data/lib/kowl/templates/config/db/sqlserver.yml.tt +28 -0
  119. data/lib/kowl/templates/config/initializers/administrate.rb.tt +9 -0
  120. data/lib/kowl/templates/config/initializers/bullet.rb +21 -0
  121. data/lib/kowl/templates/config/initializers/devise-security.rb +44 -0
  122. data/lib/kowl/templates/config/initializers/devise_argon2.rb +29 -0
  123. data/lib/kowl/templates/config/initializers/faker.rb +6 -0
  124. data/lib/kowl/templates/config/initializers/generators.rb.tt +31 -0
  125. data/lib/kowl/templates/config/initializers/geocoder.rb +10 -0
  126. data/lib/kowl/templates/config/initializers/letter_opener.rb +13 -0
  127. data/lib/kowl/templates/config/initializers/lockbox.rb +11 -0
  128. data/lib/kowl/templates/config/initializers/logging.rb +6 -0
  129. data/lib/kowl/templates/config/initializers/lograge.rb +7 -0
  130. data/lib/kowl/templates/config/initializers/logstop.rb +4 -0
  131. data/lib/kowl/templates/config/initializers/middleware.rb +9 -0
  132. data/lib/kowl/templates/config/initializers/oj.rb +7 -0
  133. data/lib/kowl/templates/config/initializers/pagy.rb.tt +16 -0
  134. data/lib/kowl/templates/config/initializers/postmark.rb +8 -0
  135. data/lib/kowl/templates/config/initializers/rack_attack.rb.tt +71 -0
  136. data/lib/kowl/templates/config/initializers/sass.rb +5 -0
  137. data/lib/kowl/templates/config/initializers/sidekiq.rb +11 -0
  138. data/lib/kowl/templates/config/initializers/simpleform/semantic.rb +225 -0
  139. data/lib/kowl/templates/config/initializers/slim.rb +6 -0
  140. data/lib/kowl/templates/config/initializers/sparkpost.rb +13 -0
  141. data/lib/kowl/templates/config/routes.rb.tt +28 -0
  142. data/lib/kowl/templates/config/sidekiq.yml.tt +17 -0
  143. data/lib/kowl/templates/db/migrations/create_action_text_tables.action_text.rb.tt +16 -0
  144. data/lib/kowl/templates/db/migrations/create_active_storage_tables.active_storage.rb.tt +29 -0
  145. data/lib/kowl/templates/db/migrations/devise.rb.tt +59 -0
  146. data/lib/kowl/templates/db/migrations/login_activities.rb.tt +41 -0
  147. data/lib/kowl/templates/db/seeds.rb.tt +14 -0
  148. data/lib/kowl/templates/docker/Dockerfile.alpine.tt +92 -0
  149. data/lib/kowl/templates/docker/Dockerfile.debian.tt +133 -0
  150. data/lib/kowl/templates/docker/docker-compose.yml.tt +55 -0
  151. data/lib/kowl/templates/docker/mysql/Dockerfile.tt +15 -0
  152. data/lib/kowl/templates/dotfiles/Aptfile.tt +34 -0
  153. data/lib/kowl/templates/dotfiles/Brewfile.tt +49 -0
  154. data/lib/kowl/templates/dotfiles/Procfile.tt +12 -0
  155. data/lib/kowl/templates/dotfiles/codeclimate.yml +76 -0
  156. data/lib/kowl/templates/dotfiles/coffeelint.json +10 -0
  157. data/lib/kowl/templates/dotfiles/coffeelintignore +15 -0
  158. data/lib/kowl/templates/dotfiles/dockerignore +23 -0
  159. data/lib/kowl/templates/dotfiles/editorconfig +13 -0
  160. data/lib/kowl/templates/dotfiles/env.tt +58 -0
  161. data/lib/kowl/templates/dotfiles/erb-lint.yml +10 -0
  162. data/lib/kowl/templates/dotfiles/erdconfig.tt +24 -0
  163. data/lib/kowl/templates/dotfiles/eslintignore +20 -0
  164. data/lib/kowl/templates/dotfiles/eslintrc.js +31 -0
  165. data/lib/kowl/templates/dotfiles/fasterer.yml +14 -0
  166. data/lib/kowl/templates/dotfiles/foreman +1 -0
  167. data/lib/kowl/templates/dotfiles/gitattributes +15 -0
  168. data/lib/kowl/templates/dotfiles/gitignore +69 -0
  169. data/lib/kowl/templates/dotfiles/haml-lint.yml +23 -0
  170. data/lib/kowl/templates/dotfiles/jsbeautifyrc +15 -0
  171. data/lib/kowl/templates/dotfiles/jshintrc +3 -0
  172. data/lib/kowl/templates/dotfiles/mailmap +3 -0
  173. data/lib/kowl/templates/dotfiles/nvmrc +1 -0
  174. data/lib/kowl/templates/dotfiles/prettierignore +21 -0
  175. data/lib/kowl/templates/dotfiles/prettierrc.js +62 -0
  176. data/lib/kowl/templates/dotfiles/pryrc +7 -0
  177. data/lib/kowl/templates/dotfiles/rspec +3 -0
  178. data/lib/kowl/templates/dotfiles/rubocop.yml.tt +78 -0
  179. data/lib/kowl/templates/dotfiles/scss-lint.yml +132 -0
  180. data/lib/kowl/templates/dotfiles/simplecov +19 -0
  181. data/lib/kowl/templates/dotfiles/slim-lint.yml +23 -0
  182. data/lib/kowl/templates/dotfiles/slugignore +10 -0
  183. data/lib/kowl/templates/dotfiles/yamllint +7 -0
  184. data/lib/kowl/templates/dotfiles/yarnclean +46 -0
  185. data/lib/kowl/templates/lib/tasks/stats.rake +42 -0
  186. data/lib/kowl/templates/tests/factories/README.md +0 -0
  187. data/lib/kowl/templates/tests/factories/login_activity.rb +11 -0
  188. data/lib/kowl/templates/tests/factories/user.rb +11 -0
  189. data/lib/kowl/templates/tests/minitest/README.md +3 -0
  190. data/lib/kowl/templates/tests/minitest/application_system_test_case.rb +7 -0
  191. data/lib/kowl/templates/tests/minitest/controllers/pages_controller_test.rb +10 -0
  192. data/lib/kowl/templates/tests/minitest/models/login_activity_test.rb +8 -0
  193. data/lib/kowl/templates/tests/minitest/models/user_test.rb +15 -0
  194. data/lib/kowl/templates/tests/minitest/policies/login_activity_policy_test.rb +7 -0
  195. data/lib/kowl/templates/tests/minitest/policies/user_policy_test.rb +7 -0
  196. data/lib/kowl/templates/tests/minitest/support/capybara.rb +38 -0
  197. data/lib/kowl/templates/tests/minitest/support/database_cleaner.rb +20 -0
  198. data/lib/kowl/templates/tests/minitest/support/database_cleaner_support.rb +15 -0
  199. data/lib/kowl/templates/tests/minitest/support/deferred_garbage_collection.rb +21 -0
  200. data/lib/kowl/templates/tests/minitest/support/devise.rb +16 -0
  201. data/lib/kowl/templates/tests/minitest/support/factories.rb +6 -0
  202. data/lib/kowl/templates/tests/minitest/support/formulaic.rb +8 -0
  203. data/lib/kowl/templates/tests/minitest/support/helpers/devise_helper.rb +57 -0
  204. data/lib/kowl/templates/tests/minitest/support/papertrail.rb +17 -0
  205. data/lib/kowl/templates/tests/minitest/support/pundit.rb +0 -0
  206. data/lib/kowl/templates/tests/minitest/support/shoulda.rb +11 -0
  207. data/lib/kowl/templates/tests/minitest/support/simplecov.rb +8 -0
  208. data/lib/kowl/templates/tests/minitest/test_helper.rb +17 -0
  209. data/lib/kowl/templates/tests/rspec/README.md +9 -0
  210. data/lib/kowl/templates/tests/rspec/controllers/admin/application_controller_spec.rb +12 -0
  211. data/lib/kowl/templates/tests/rspec/controllers/admin/users_controller_spec.rb +14 -0
  212. data/lib/kowl/templates/tests/rspec/controllers/pages_controller_spec.rb +10 -0
  213. data/lib/kowl/templates/tests/rspec/features/README.md +15 -0
  214. data/lib/kowl/templates/tests/rspec/features/visitor_sign_up_spec.rb +25 -0
  215. data/lib/kowl/templates/tests/rspec/helpers/application_helper_spec.rb +7 -0
  216. data/lib/kowl/templates/tests/rspec/helpers/pages_helper_spec.rb +15 -0
  217. data/lib/kowl/templates/tests/rspec/models/login_activity_spec.rb +11 -0
  218. data/lib/kowl/templates/tests/rspec/models/user_spec.rb +21 -0
  219. data/lib/kowl/templates/tests/rspec/policies/login_activity_policy_spec.rb +59 -0
  220. data/lib/kowl/templates/tests/rspec/policies/user_policy_spec.rb +56 -0
  221. data/lib/kowl/templates/tests/rspec/rails_helper.rb +72 -0
  222. data/lib/kowl/templates/tests/rspec/requests/pages_spec.rb +11 -0
  223. data/lib/kowl/templates/tests/rspec/spec_helper.rb +96 -0
  224. data/lib/kowl/templates/tests/rspec/support/bullet.rb +17 -0
  225. data/lib/kowl/templates/tests/rspec/support/capybara.rb +37 -0
  226. data/lib/kowl/templates/tests/rspec/support/controller_testing.rb +10 -0
  227. data/lib/kowl/templates/tests/rspec/support/database_cleaner.rb +55 -0
  228. data/lib/kowl/templates/tests/rspec/support/deferred_garbage_collection.rb +32 -0
  229. data/lib/kowl/templates/tests/rspec/support/devise.rb +21 -0
  230. data/lib/kowl/templates/tests/rspec/support/factories.rb +5 -0
  231. data/lib/kowl/templates/tests/rspec/support/formulaic.rb +8 -0
  232. data/lib/kowl/templates/tests/rspec/support/helpers/devise_helpers.rb +56 -0
  233. data/lib/kowl/templates/tests/rspec/support/papertrail.rb +5 -0
  234. data/lib/kowl/templates/tests/rspec/support/pi_ci.rb +6 -0
  235. data/lib/kowl/templates/tests/rspec/support/pundit.rb +6 -0
  236. data/lib/kowl/templates/tests/rspec/support/shoulda.rb +10 -0
  237. data/lib/kowl/templates/tests/rspec/support/sidekiq.rb +10 -0
  238. data/lib/kowl/templates/tests/rspec/support/simplecov.rb +7 -0
  239. data/lib/kowl/templates/tests/rspec/support/warden.rb +8 -0
  240. data/lib/kowl/templates/text_files/AUTHORS.md +4 -0
  241. data/lib/kowl/templates/text_files/CHANGELOG.md.tt +12 -0
  242. data/lib/kowl/templates/text_files/CODE_OF_CONDUCT.md +76 -0
  243. data/lib/kowl/templates/text_files/TODO.md +7 -0
  244. data/lib/kowl/templates/text_files/VERSION +1 -0
  245. data/lib/kowl/templates/text_files/humans.txt.tt +15 -0
  246. data/lib/kowl/templates/text_files/robots.txt.tt +6 -0
  247. data/lib/kowl/templates/text_files/security.txt +6 -0
  248. data/lib/kowl/version.rb +9 -0
  249. data/lib/kowl.rb +18 -0
  250. 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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Set locale as en-US for generating US styled addresses and phone numbers
4
+ if defined?(Faker)
5
+ Faker::Config.locale = 'en-US'
6
+ 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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Geocoder)
4
+ Geocoder.configure(
5
+ ip_lookup: :geoip2,
6
+ geoip2: {
7
+ file: Rails.root.join('db', 'maxmind/GeoLite2-City.mmdb')
8
+ }
9
+ )
10
+ 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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://api.rubyonrails.org/classes/ActiveSupport/Logger.html
4
+ unless Rails.env.test?
5
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Lograge)
4
+ Rails.application.configure do
5
+ config.lograge.enabled = true
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://github.com/ankane/logstop
4
+ Logstop.guard(Rails.logger) if defined?(Logstop)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.middleware do |m|
4
+ # enable gzip asset compressing to reduce the page size
5
+ m.use Rack::Deflater
6
+
7
+ # enable Rack-Attack to prevent credential stuffing
8
+ m.use Rack::Attack
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Oj)
4
+ # https://www.rubydoc.info/gems/oj/2.12.11
5
+ # https://www.rubydoc.info/gems/oj/Oj.default_options
6
+ Oj.default_options = { mode: :compat, time_format: :ruby, use_to_json: true }
7
+ 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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ if Rails.env.production?
4
+ Rails.application.config do |c|
5
+ config.action_mailer.delivery_method = :postmark
6
+ config.action_mailer.postmark_settings = { api_token: ENV['POSTMARK_API_TOKEN'] }
7
+ end
8
+ 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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.sass.preferred_syntax = :scss
4
+ # disable comments in sass/scss assets
5
+ Rails.application.config.sass.line_comments = false
@@ -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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Slim)
4
+ # https://www.rubydoc.info/gems/slim/frames#Configuring_Slim
5
+ Slim::Engine.set_options pretty: false, tabsize: 2
6
+ 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