kowl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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