plutonium 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.ruby-version +1 -0
  4. data/.standard.yml +4 -0
  5. data/.vscode/extensions.json +15 -0
  6. data/.vscode/launch.json +7 -0
  7. data/.vscode/settings.json +35 -0
  8. data/CHANGELOG.md +5 -0
  9. data/LICENSE.txt +21 -0
  10. data/README copy.md +84 -0
  11. data/README.md +67 -0
  12. data/Rakefile +8 -0
  13. data/app/views/layouts/resource.html.erb +43 -0
  14. data/app/views/resource/_color_modes.html.erb +55 -0
  15. data/app/views/resource/_details.html.erb +6 -0
  16. data/app/views/resource/_empty_card.html.erb +12 -0
  17. data/app/views/resource/_flash.html.erb +9 -0
  18. data/app/views/resource/_form.html.erb +32 -0
  19. data/app/views/resource/_header.html.erb +8 -0
  20. data/app/views/resource/_interactive_resource_action_form.html.erb +67 -0
  21. data/app/views/resource/_messages.html.erb +1 -0
  22. data/app/views/resource/_metric_card.html.erb +16 -0
  23. data/app/views/resource/_nav_user.html.erb +4 -0
  24. data/app/views/resource/_pagination.html.erb +6 -0
  25. data/app/views/resource/_pagy_pagination.html.erb +15 -0
  26. data/app/views/resource/_resource.html.erb +1 -0
  27. data/app/views/resource/_resource.rabl +5 -0
  28. data/app/views/resource/_sidebar.html.erb +11 -0
  29. data/app/views/resource/_sidebar_menu.html.erb +1 -0
  30. data/app/views/resource/_tab_menu.html.erb +13 -0
  31. data/app/views/resource/_table.html.erb +78 -0
  32. data/app/views/resource/_table_actions.html.erb +15 -0
  33. data/app/views/resource/_toast.html.erb +26 -0
  34. data/app/views/resource/_toolbar.html.erb +22 -0
  35. data/app/views/resource/_toolbar_actions.html.erb +16 -0
  36. data/app/views/resource/_toolbar_breadcrumbs.html.erb +32 -0
  37. data/app/views/resource/_toolbar_search_input.erb +27 -0
  38. data/app/views/resource/edit.html.erb +10 -0
  39. data/app/views/resource/errors.rabl +3 -0
  40. data/app/views/resource/index.html.erb +19 -0
  41. data/app/views/resource/index.rabl +3 -0
  42. data/app/views/resource/interactive_resource_collection_action.html.erb +11 -0
  43. data/app/views/resource/interactive_resource_record_action.html.erb +11 -0
  44. data/app/views/resource/interactive_resource_recordless_action.html.erb +11 -0
  45. data/app/views/resource/new.html.erb +11 -0
  46. data/app/views/resource/readme.md +16 -0
  47. data/app/views/resource/show.html.erb +14 -0
  48. data/app/views/resource/show.rabl +3 -0
  49. data/brakeman.ignore +51 -0
  50. data/lib/active_model/validations/array_validator.rb +74 -0
  51. data/lib/active_model/validations/attached_validator.rb +17 -0
  52. data/lib/active_model/validations/url_validator.rb +51 -0
  53. data/lib/generators/pu/core/install/install_generator.rb +43 -0
  54. data/lib/generators/pu/core/install/templates/.keep +0 -0
  55. data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +2 -0
  56. data/lib/generators/pu/core/install/templates/app/interactions/resource_interaction.rb.tt +2 -0
  57. data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +5 -0
  58. data/lib/generators/pu/core/install/templates/app/policies/resource_policy.rb.tt +2 -0
  59. data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +2 -0
  60. data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +2 -0
  61. data/lib/generators/pu/core/install/templates/config/packages.rb +3 -0
  62. data/lib/generators/pu/gem/pagy/pagy_generator.rb +25 -0
  63. data/lib/generators/pu/gem/pagy/templates/.keep +0 -0
  64. data/lib/generators/pu/gem/pagy/templates/config/initializers/pagy.rb +4 -0
  65. data/lib/generators/pu/gem/rabl/rabl_generator.rb +25 -0
  66. data/lib/generators/pu/gem/rabl/templates/.keep +0 -0
  67. data/lib/generators/pu/gem/rabl/templates/config/initializers/rabl.rb +60 -0
  68. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +25 -0
  69. data/lib/generators/pu/gem/simple_form/templates/.keep +0 -0
  70. data/lib/generators/pu/gen/pug/pug_generator.rb +43 -0
  71. data/lib/generators/pu/gen/pug/templates/pug.rb.tt +23 -0
  72. data/lib/generators/pu/pkg/app/app_generator.rb +60 -0
  73. data/lib/generators/pu/pkg/app/templates/app/controllers/resource_controller.rb.tt +26 -0
  74. data/lib/generators/pu/pkg/app/templates/app/interactions/resource_interaction.rb.tt +4 -0
  75. data/lib/generators/pu/pkg/app/templates/app/policies/resource_policy.rb.tt +4 -0
  76. data/lib/generators/pu/pkg/app/templates/app/presenters/resource_presenter.rb.tt +4 -0
  77. data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +17 -0
  78. data/lib/generators/pu/pkg/app/templates/lib/engine.rb.tt +14 -0
  79. data/lib/generators/pu/pkg/feature/feature_generator.rb +44 -0
  80. data/lib/generators/pu/pkg/feature/templates/.keep +0 -0
  81. data/lib/generators/pu/pkg/feature/templates/app/controllers/resource_controller.rb.tt +7 -0
  82. data/lib/generators/pu/pkg/feature/templates/app/interactions/resource_interaction.rb.tt +4 -0
  83. data/lib/generators/pu/pkg/feature/templates/app/models/resource_record.rb.tt +5 -0
  84. data/lib/generators/pu/pkg/feature/templates/app/policies/resource_policy.rb.tt +4 -0
  85. data/lib/generators/pu/pkg/feature/templates/app/presenters/resource_presenter.rb.tt +4 -0
  86. data/lib/generators/pu/pkg/feature/templates/lib/engine.rb.tt +8 -0
  87. data/lib/generators/pu/resource/conn/conn_generator.rb +54 -0
  88. data/lib/generators/pu/resource/conn/templates/.keep +0 -0
  89. data/lib/generators/pu/resource/conn/templates/app/controllers/resource_controller.rb.tt +3 -0
  90. data/lib/generators/pu/resource/conn/templates/app/policies/resource_policy.rb.tt +3 -0
  91. data/lib/generators/pu/resource/conn/templates/app/presenters/resource_presenter.rb.tt +3 -0
  92. data/lib/generators/pu/resource/model/USAGE +113 -0
  93. data/lib/generators/pu/resource/model/model_generator.rb +163 -0
  94. data/lib/generators/pu/resource/model/templates/controller.rb.tt +5 -0
  95. data/lib/generators/pu/resource/model/templates/create_table_migration.rb.tt +26 -0
  96. data/lib/generators/pu/resource/model/templates/model.rb.tt +53 -0
  97. data/lib/generators/pu/resource/model/templates/module.rb.tt +7 -0
  98. data/lib/generators/pu/resource/model/templates/policy.rb.tt +4 -0
  99. data/lib/generators/pu/resource/model/templates/presenter.rb.tt +4 -0
  100. data/lib/generators/pu/resource/scaffold/scaffold_generator.rb +219 -0
  101. data/lib/generators/pu/resource/scaffold/templates/app/controllers/admin_resources/resource_controller.rb.tt +7 -0
  102. data/lib/generators/pu/resource/scaffold/templates/app/controllers/entity_resources/resource_controller.rb.tt +7 -0
  103. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/admin/resource_policy.rb.tt +22 -0
  104. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/entity/resource_policy.rb.tt +22 -0
  105. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/resource_policy.rb.tt +13 -0
  106. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/admin_presenter.rb.tt +7 -0
  107. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/entity_presenter.rb.tt +7 -0
  108. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/presenter.rb.tt +23 -0
  109. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.html.erb.tt +3 -0
  110. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.rabl +7 -0
  111. data/lib/generators/pu/rodauth/account_generator.rb +120 -0
  112. data/lib/generators/pu/rodauth/concerns/account_selector.rb +22 -0
  113. data/lib/generators/pu/rodauth/concerns/configuration.rb +211 -0
  114. data/lib/generators/pu/rodauth/concerns/feature_selector.rb +125 -0
  115. data/lib/generators/pu/rodauth/install_generator.rb +69 -0
  116. data/lib/generators/pu/rodauth/migration/active_record/account_expiration.erb +8 -0
  117. data/lib/generators/pu/rodauth/migration/active_record/active_sessions.erb +7 -0
  118. data/lib/generators/pu/rodauth/migration/active_record/audit_logging.erb +16 -0
  119. data/lib/generators/pu/rodauth/migration/active_record/base.erb +22 -0
  120. data/lib/generators/pu/rodauth/migration/active_record/disallow_password_reuse.erb +5 -0
  121. data/lib/generators/pu/rodauth/migration/active_record/email_auth.erb +8 -0
  122. data/lib/generators/pu/rodauth/migration/active_record/jwt_refresh.erb +7 -0
  123. data/lib/generators/pu/rodauth/migration/active_record/lockout.erb +13 -0
  124. data/lib/generators/pu/rodauth/migration/active_record/otp.erb +8 -0
  125. data/lib/generators/pu/rodauth/migration/active_record/password_expiration.erb +6 -0
  126. data/lib/generators/pu/rodauth/migration/active_record/recovery_codes.erb +6 -0
  127. data/lib/generators/pu/rodauth/migration/active_record/remember.erb +7 -0
  128. data/lib/generators/pu/rodauth/migration/active_record/reset_password.erb +8 -0
  129. data/lib/generators/pu/rodauth/migration/active_record/separate_passwords.erb +5 -0
  130. data/lib/generators/pu/rodauth/migration/active_record/single_session.erb +6 -0
  131. data/lib/generators/pu/rodauth/migration/active_record/sms_codes.erb +9 -0
  132. data/lib/generators/pu/rodauth/migration/active_record/verify_account.erb +8 -0
  133. data/lib/generators/pu/rodauth/migration/active_record/verify_login_change.erb +8 -0
  134. data/lib/generators/pu/rodauth/migration/active_record/webauthn.erb +13 -0
  135. data/lib/generators/pu/rodauth/migration/sequel/account_expiration.erb +7 -0
  136. data/lib/generators/pu/rodauth/migration/sequel/active_sessions.erb +8 -0
  137. data/lib/generators/pu/rodauth/migration/sequel/audit_logging.erb +17 -0
  138. data/lib/generators/pu/rodauth/migration/sequel/base.erb +25 -0
  139. data/lib/generators/pu/rodauth/migration/sequel/disallow_password_reuse.erb +6 -0
  140. data/lib/generators/pu/rodauth/migration/sequel/email_auth.erb +7 -0
  141. data/lib/generators/pu/rodauth/migration/sequel/jwt_refresh.erb +8 -0
  142. data/lib/generators/pu/rodauth/migration/sequel/lockout.erb +11 -0
  143. data/lib/generators/pu/rodauth/migration/sequel/otp.erb +7 -0
  144. data/lib/generators/pu/rodauth/migration/sequel/password_expiration.erb +5 -0
  145. data/lib/generators/pu/rodauth/migration/sequel/recovery_codes.erb +6 -0
  146. data/lib/generators/pu/rodauth/migration/sequel/remember.erb +6 -0
  147. data/lib/generators/pu/rodauth/migration/sequel/reset_password.erb +7 -0
  148. data/lib/generators/pu/rodauth/migration/sequel/separate_passwords.erb +6 -0
  149. data/lib/generators/pu/rodauth/migration/sequel/single_session.erb +5 -0
  150. data/lib/generators/pu/rodauth/migration/sequel/sms_codes.erb +8 -0
  151. data/lib/generators/pu/rodauth/migration/sequel/verify_account.erb +7 -0
  152. data/lib/generators/pu/rodauth/migration/sequel/verify_login_change.erb +7 -0
  153. data/lib/generators/pu/rodauth/migration/sequel/webauthn.erb +13 -0
  154. data/lib/generators/pu/rodauth/migration_generator.rb +190 -0
  155. data/lib/generators/pu/rodauth/templates/INSTRUCTIONS +52 -0
  156. data/lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt +6 -0
  157. data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +3 -0
  158. data/lib/generators/pu/rodauth/templates/app/mailers/account_mailer.rb.tt +4 -0
  159. data/lib/generators/pu/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +62 -0
  160. data/lib/generators/pu/rodauth/templates/app/misc/account_rodauth_plugin.rb.tt +255 -0
  161. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_app.rb.tt +24 -0
  162. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_plugin.rb.tt +234 -0
  163. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +40 -0
  164. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +7 -0
  165. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form.html.erb +26 -0
  166. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +9 -0
  167. data/lib/generators/pu/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +6 -0
  168. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_login.html.erb +27 -0
  169. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_password.html.erb +27 -0
  170. data/lib/generators/pu/rodauth/templates/app/views/rodauth/close_account.html.erb +13 -0
  171. data/lib/generators/pu/rodauth/templates/app/views/rodauth/confirm_password.html.erb +11 -0
  172. data/lib/generators/pu/rodauth/templates/app/views/rodauth/create_account.html.erb +35 -0
  173. data/lib/generators/pu/rodauth/templates/app/views/rodauth/email_auth.html.erb +5 -0
  174. data/lib/generators/pu/rodauth/templates/app/views/rodauth/login.html.erb +4 -0
  175. data/lib/generators/pu/rodauth/templates/app/views/rodauth/logout.html.erb +14 -0
  176. data/lib/generators/pu/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +3 -0
  177. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_auth.html.erb +15 -0
  178. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_disable.html.erb +13 -0
  179. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_setup.html.erb +41 -0
  180. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +11 -0
  181. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +13 -0
  182. data/lib/generators/pu/rodauth/templates/app/views/rodauth/remember.html.erb +22 -0
  183. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password.html.erb +19 -0
  184. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +17 -0
  185. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_auth.html.erb +15 -0
  186. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +15 -0
  187. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_disable.html.erb +13 -0
  188. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_request.html.erb +5 -0
  189. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_setup.html.erb +23 -0
  190. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_email_auth_request_form.html.erb +5 -0
  191. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form.html.erb +24 -0
  192. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form_footer.html.erb +7 -0
  193. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/add_recovery_codes.html.erb +16 -0
  194. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_login.html.erb +25 -0
  195. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_password.html.erb +25 -0
  196. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/close_account.html.erb +11 -0
  197. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/confirm_password.html.erb +19 -0
  198. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/create_account.html.erb +33 -0
  199. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/email_auth.html.erb +3 -0
  200. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/login.html.erb +5 -0
  201. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/logout.html.erb +10 -0
  202. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/multi_phase_login.html.erb +5 -0
  203. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_auth.html.erb +9 -0
  204. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_disable.html.erb +11 -0
  205. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_setup.html.erb +32 -0
  206. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_auth.html.erb +9 -0
  207. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_codes.html.erb +11 -0
  208. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/remember.html.erb +18 -0
  209. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password.html.erb +17 -0
  210. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password_request.html.erb +17 -0
  211. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_auth.html.erb +9 -0
  212. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_confirm.html.erb +9 -0
  213. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_disable.html.erb +11 -0
  214. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_request.html.erb +3 -0
  215. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_setup.html.erb +17 -0
  216. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_auth.html.erb +5 -0
  217. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_disable.html.erb +11 -0
  218. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_manage.html.erb +26 -0
  219. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account.html.erb +15 -0
  220. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account_request.html.erb +9 -0
  221. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account.html.erb +19 -0
  222. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account_resend.html.erb +17 -0
  223. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_login_change.html.erb +3 -0
  224. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_auth.html.erb +13 -0
  225. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_autofill.html.erb +10 -0
  226. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_remove.html.erb +21 -0
  227. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_setup.html.erb +21 -0
  228. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +5 -0
  229. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +13 -0
  230. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +22 -0
  231. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account.html.erb +15 -0
  232. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +9 -0
  233. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account.html.erb +21 -0
  234. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +17 -0
  235. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +5 -0
  236. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +15 -0
  237. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +10 -0
  238. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +23 -0
  239. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +23 -0
  240. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb +5 -0
  241. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/password_changed.text.erb +2 -0
  242. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb +5 -0
  243. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password_notify.text.erb +2 -0
  244. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +5 -0
  245. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb +4 -0
  246. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +10 -0
  247. data/lib/generators/pu/rodauth/templates/config/initializers/rodauth.rb.tt +3 -0
  248. data/lib/generators/pu/rodauth/templates/db/migrate/create_rodauth.rb.tt +13 -0
  249. data/lib/generators/pu/rodauth/views_generator.rb +125 -0
  250. data/lib/plutonium/auth/public_access.rb +17 -0
  251. data/lib/plutonium/auth/rodauth.rb +35 -0
  252. data/lib/plutonium/auth.rb +12 -0
  253. data/lib/plutonium/config.rb +11 -0
  254. data/lib/plutonium/core/.DS_Store +0 -0
  255. data/lib/plutonium/core/action.rb +46 -0
  256. data/lib/plutonium/core/actions/basic_action.rb +16 -0
  257. data/lib/plutonium/core/actions/collection.rb +33 -0
  258. data/lib/plutonium/core/actions/destroy_action.rb +21 -0
  259. data/lib/plutonium/core/actions/edit_action.rb +19 -0
  260. data/lib/plutonium/core/actions/interactive_action.rb +64 -0
  261. data/lib/plutonium/core/actions/new_action.rb +18 -0
  262. data/lib/plutonium/core/actions/show_action.rb +17 -0
  263. data/lib/plutonium/core/actions.rb +17 -0
  264. data/lib/plutonium/core/app_controller.rb +121 -0
  265. data/lib/plutonium/core/autodiscovery/discoverer.rb +15 -0
  266. data/lib/plutonium/core/autodiscovery/input_discoverer.rb +33 -0
  267. data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +33 -0
  268. data/lib/plutonium/core/autodiscovery.rb +13 -0
  269. data/lib/plutonium/core/controllers/authorizable.rb +56 -0
  270. data/lib/plutonium/core/controllers/bootable.rb +44 -0
  271. data/lib/plutonium/core/controllers/crud_actions.rb +128 -0
  272. data/lib/plutonium/core/controllers/entity_scoping.rb +69 -0
  273. data/lib/plutonium/core/controllers/interactive_actions.rb +210 -0
  274. data/lib/plutonium/core/controllers/presentable.rb +59 -0
  275. data/lib/plutonium/core/controllers.rb +16 -0
  276. data/lib/plutonium/core/definers/action_definer.rb +25 -0
  277. data/lib/plutonium/core/definers/field_definer.rb +19 -0
  278. data/lib/plutonium/core/definers/input_definer.rb +37 -0
  279. data/lib/plutonium/core/definers/renderer_definer.rb +35 -0
  280. data/lib/plutonium/core/definers.rb +14 -0
  281. data/lib/plutonium/core/fields/inputs/association_input.rb +26 -0
  282. data/lib/plutonium/core/fields/inputs/basic_input.rb +42 -0
  283. data/lib/plutonium/core/fields/inputs/belongs_to_input.rb +15 -0
  284. data/lib/plutonium/core/fields/inputs/factory.rb +58 -0
  285. data/lib/plutonium/core/fields/inputs/has_many_input.rb +15 -0
  286. data/lib/plutonium/core/fields/inputs/noop_input.rb +19 -0
  287. data/lib/plutonium/core/fields/inputs.rb +18 -0
  288. data/lib/plutonium/core/fields/renderers/association_renderer.rb +25 -0
  289. data/lib/plutonium/core/fields/renderers/basic_renderer.rb +27 -0
  290. data/lib/plutonium/core/fields/renderers/factory.rb +52 -0
  291. data/lib/plutonium/core/fields/renderers.rb +15 -0
  292. data/lib/plutonium/core/fields.rb +12 -0
  293. data/lib/plutonium/core/ui/collection.rb +14 -0
  294. data/lib/plutonium/core/ui/detail.rb +11 -0
  295. data/lib/plutonium/core/ui/form.rb +11 -0
  296. data/lib/plutonium/core/ui.rb +13 -0
  297. data/lib/plutonium/core.rb +16 -0
  298. data/lib/plutonium/helpers/action_buttons_helper.rb +32 -0
  299. data/lib/plutonium/helpers/application_helper.rb +22 -0
  300. data/lib/plutonium/helpers/attachment_helper.rb +62 -0
  301. data/lib/plutonium/helpers/content_helper.rb +66 -0
  302. data/lib/plutonium/helpers/display_helper.rb +83 -0
  303. data/lib/plutonium/helpers/form_helper.rb +24 -0
  304. data/lib/plutonium/helpers/menu_helper.rb +69 -0
  305. data/lib/plutonium/helpers/pagination_helper.rb +9 -0
  306. data/lib/plutonium/helpers/turbo_helper.rb +13 -0
  307. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +9 -0
  308. data/lib/plutonium/helpers.rb +31 -0
  309. data/lib/plutonium/initializers/TODO +2 -0
  310. data/lib/plutonium/initializers/pagy.rb +5 -0
  311. data/lib/plutonium/initializers/patches.rb +2 -0
  312. data/lib/plutonium/initializers/rabl.rb +60 -0
  313. data/lib/plutonium/initializers/simple_form.rb +405 -0
  314. data/lib/plutonium/lib/after_commit.rb +34 -0
  315. data/lib/plutonium/lib/bit_flags.rb +36 -0
  316. data/lib/plutonium/packaging/app.rb +125 -0
  317. data/lib/plutonium/packaging/feature.rb +18 -0
  318. data/lib/plutonium/packaging/package.rb +22 -0
  319. data/lib/plutonium/packaging.rb +9 -0
  320. data/lib/plutonium/policy/initializer.rb +22 -0
  321. data/lib/plutonium/policy/scope.rb +19 -0
  322. data/lib/plutonium/policy.rb +8 -0
  323. data/lib/plutonium/preserved__/field.rb +65 -0
  324. data/lib/plutonium/preserved__/input.rb +93 -0
  325. data/lib/plutonium/reactor/core.rb +61 -0
  326. data/lib/plutonium/reactor/resource_context.rb +15 -0
  327. data/lib/plutonium/reactor/resource_controller.rb +108 -0
  328. data/lib/plutonium/reactor/resource_interaction.rb +8 -0
  329. data/lib/plutonium/reactor/resource_policy.rb +105 -0
  330. data/lib/plutonium/reactor/resource_presenter.rb +42 -0
  331. data/lib/plutonium/reactor/resource_record.rb +123 -0
  332. data/lib/plutonium/reactor.rb +13 -0
  333. data/lib/plutonium/refinements/parameter_refinements.rb +26 -0
  334. data/lib/plutonium/simple_form_components/attachment_component.rb +77 -0
  335. data/lib/plutonium/simple_form_components/input_group_component.rb +14 -0
  336. data/lib/plutonium/version.rb +3 -0
  337. data/lib/plutonium.rb +31 -0
  338. data/plutonium.gemspec +47 -0
  339. data/public/.keep +0 -0
  340. data/public/plutonium-assets/application.css +24280 -0
  341. data/public/plutonium-assets/application.js +31420 -0
  342. data/public/plutonium-assets/fonts/bootstrap-icons.woff +0 -0
  343. data/public/plutonium-assets/fonts/bootstrap-icons.woff2 +0 -0
  344. data/public/plutonium-assets/logo.png +0 -0
  345. data/sig/plutonium.rbs +4 -0
  346. metadata +519 -0
@@ -0,0 +1,5 @@
1
+ Someone has requested a login link for the account with this email
2
+ address. If you did not request a login link, please ignore this
3
+ message. If you requested a login link, please go to
4
+ <%= @rodauth.email_auth_email_link %>
5
+ to login to this account.
@@ -0,0 +1,2 @@
1
+ Someone (hopefully you) has changed the password for the account
2
+ associated to this email address.
@@ -0,0 +1,5 @@
1
+ Someone has requested a password reset for the account with this email
2
+ address. If you did not request a password reset, please ignore this
3
+ message. If you requested a password reset, please go to
4
+ <%= @rodauth.reset_password_email_link %>
5
+ to reset the password for the account.
@@ -0,0 +1,2 @@
1
+ Someone (hopefully you) has reset the password for the account
2
+ associated to this email address.
@@ -0,0 +1,5 @@
1
+ Someone has requested that the account with this email be unlocked.
2
+ If you did not request the unlocking of this account, please ignore this
3
+ message. If you requested the unlocking of this account, please go to
4
+ <%= @rodauth.unlock_account_email_link %>
5
+ to unlock this account.
@@ -0,0 +1,4 @@
1
+ Someone has created an account with this email address. If you did not create
2
+ this account, please ignore this message. If you created this account, please go to
3
+ <%= @rodauth.verify_account_email_link %>
4
+ to verify the account.
@@ -0,0 +1,10 @@
1
+ Someone with an account has requested their login be changed to this email address:
2
+
3
+ Old email: <%= @account.email %>
4
+
5
+ New email: <%= @new_email %>
6
+
7
+ If you did not request this login change, please ignore this message. If you
8
+ requested this login change, please go to
9
+ <%= @rodauth.verify_login_change_email_link %>
10
+ to verify the login change.
@@ -0,0 +1,3 @@
1
+ Rodauth::Rails.configure do |config|
2
+ config.app = "RodauthApp"
3
+ end
@@ -0,0 +1,13 @@
1
+ <% if defined?(::ActiveRecord::Railtie) -%>
2
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
3
+ def change
4
+ <%= migration_content -%>
5
+ end
6
+ end
7
+ <% else -%>
8
+ Sequel.migration do
9
+ change do
10
+ <%= migration_content -%>
11
+ end
12
+ end
13
+ <% end -%>
@@ -0,0 +1,125 @@
1
+ return unless defined?(Rodauth::Rails)
2
+
3
+ require "rails/generators/base"
4
+
5
+ require "#{__dir__}/concerns/configuration"
6
+
7
+ module Pu
8
+ module Rodauth
9
+ class ViewsGenerator < ::Rails::Generators::Base
10
+ include Concerns::Configuration
11
+
12
+ source_root "#{__dir__}/templates"
13
+ # namespace "rodauth:views"
14
+
15
+ desc "Generate views for selected features\n\n" \
16
+ "Supported Features\n" \
17
+ "=========================================\n" \
18
+ "#{VIEW_CONFIG.keys.sort.map(&:to_s).join "\n"}\n\n\n\n"
19
+
20
+ argument :plugin_name, type: :string, optional: true,
21
+ desc: "[CONFIG] Name of the configured rodauth app. Leave blank to use the primary account."
22
+
23
+ class_option :features, required: true, type: :array,
24
+ desc: "Rodauth features to generate views for (login, create_account, reset_password, verify_account etc.)"
25
+
26
+ class_option :all, aliases: "-a", type: :boolean,
27
+ desc: "Generates views for all Rodauth features",
28
+ default: false
29
+
30
+ class_option :css, type: :string, enum: %w[bootstrap tailwind tailwindcss],
31
+ desc: "CSS framework to generate views for",
32
+ default: "bootstrap"
33
+
34
+ def validate_selected_features
35
+ if selected_features.empty?
36
+ say "No view features specified!", :yellow
37
+ exit(1)
38
+ elsif (selected_features - view_config.keys).any?
39
+ say "No available view template for feature(s): #{(selected_features - view_config.keys).join(", ")}", :red
40
+ exit(1)
41
+ end
42
+ end
43
+
44
+ def create_views
45
+ views.each do |view|
46
+ copy_file view_location(view), "app/views/#{directory}/#{view}.html.erb" do |content|
47
+ content = content.gsub("rodauth.", "rodauth(:#{configuration_name}).") if configuration_name
48
+ content = content.gsub("rodauth/", "#{directory}/")
49
+ content = form_helpers_compatibility(content) if ActionView.version < Gem::Version.new("5.1")
50
+ content
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def features
58
+ options[:features]
59
+ end
60
+
61
+ def views
62
+ selected_features.flat_map { |feature| view_config.fetch(feature) }
63
+ end
64
+
65
+ def selected_features
66
+ if options[:all]
67
+ view_config.keys
68
+ elsif features
69
+ features.map(&:to_sym)
70
+ else
71
+ rodauth_configuration.features & view_config.keys
72
+ end
73
+ end
74
+
75
+ def directory
76
+ if controller.abstract?
77
+ raise Error, "no controller configured for configuration: #{configuration_name.inspect}"
78
+ end
79
+
80
+ controller.controller_path
81
+ end
82
+
83
+ def controller
84
+ rodauth_configuration.allocate.rails_controller
85
+ end
86
+
87
+ def rodauth_configuration
88
+ require "rodauth-rails" # this requires the project to include the package
89
+
90
+ ::Rodauth::Rails.app.rodauth!(configuration_name&.to_sym)
91
+ rescue ArgumentError => e
92
+ say "An error occurred generating views for " \
93
+ "#{configuration_name.present? ? "'#{configuration_name}'" : "primary"} account:\n\n#{e}", :red
94
+ exit(1)
95
+ end
96
+
97
+ def configuration_name
98
+ plugin_name
99
+ end
100
+
101
+ # We need to use the *_tag helpers on versions lower than Rails 5.1.
102
+ def form_helpers_compatibility(content)
103
+ content
104
+ .gsub(/form_with url: (.+) do \|form\|/, 'form_tag \1 do')
105
+ .gsub(/form\.(label|submit)/, '\1_tag')
106
+ .gsub(/form\.(email|password|text|telephone|hidden)_field (\S+), value:/, '\1_field_tag \2,')
107
+ .gsub(/form\.radio_button (\S+), (\S+),/, 'radio_button_tag \1, \2, false,')
108
+ .gsub(/form\.check_box (\S+), (.+) /, 'check_box_tag \1, "t", false, \2 ')
109
+ end
110
+
111
+ def view_location(view)
112
+ if tailwind?
113
+ "app/views/rodauth/tailwind/#{view}.html.erb"
114
+ else
115
+ "app/views/rodauth/#{view}.html.erb"
116
+ end
117
+ end
118
+
119
+ def tailwind?
120
+ ::Rails.application.config.generators.options[:rails][:template_engine] == :tailwindcss ||
121
+ options[:css]&.downcase&.start_with?("tailwind")
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,17 @@
1
+ module Plutonium
2
+ module Auth
3
+ module PublicAccess
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :current_user
8
+ end
9
+
10
+ private
11
+
12
+ def current_user
13
+ "Guest"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module Plutonium
2
+ module Auth
3
+ module Rodauth
4
+ def self.for(name)
5
+ mod = Module.new
6
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ helper_method :current_user
11
+ helper_method :logout_url
12
+ end
13
+
14
+ private
15
+
16
+ def rodauth(name = :#{name})
17
+ super(name)
18
+ end
19
+
20
+ def current_user
21
+ rodauth.rails_account
22
+ end
23
+
24
+ def logout_url
25
+ rodauth.logout_path
26
+ end
27
+
28
+ define_singleton_method(:to_s) { "Plutonium::Auth::Rodauth(:#{name})" }
29
+ define_singleton_method(:inspect) { "Plutonium::Auth::Rodautht(:#{name})" }
30
+ RUBY
31
+ mod
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module Plutonium
2
+ module Auth
3
+ extend ActiveSupport::Autoload
4
+
5
+ def self.rodauth(name)
6
+ Rodauth.for(name)
7
+ end
8
+
9
+ autoload :Rodauth
10
+ autoload :PublicAccess
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ require "active_support"
2
+
3
+ module Plutonium
4
+ module Config
5
+ mattr_accessor :reload_files
6
+ @@reload_files = defined?(Rails.env) && Rails.env.local?
7
+
8
+ mattr_accessor :cache_discovery
9
+ @@cache_discovery = defined?(Rails.env) && !Rails.env.development?
10
+ end
11
+ end
Binary file
@@ -0,0 +1,46 @@
1
+ module Plutonium
2
+ module Core
3
+ class Action
4
+ RouteOptions = Data.define :action, :method, :options do
5
+ def initialize(action: nil, method: :get, options: {})
6
+ super
7
+ end
8
+ end
9
+
10
+ attr_reader :name, :label, :icon, :route_options, :confirmation, :turbo_frame, :action_class
11
+
12
+ def initialize(name, label: nil, icon: nil, action_class: nil,
13
+ confirmation: nil,
14
+ route_options: nil, turbo_frame: nil,
15
+ collection_action: false, collection_record_action: false, record_action: false, bulk_action: false)
16
+ @name = name
17
+ @icon = icon
18
+ @label = label || name.to_s.humanize
19
+ @route_options = route_options || RouteOptions.new
20
+ @turbo_frame = turbo_frame
21
+ @action_class = action_class
22
+ @confirmation = confirmation
23
+ @collection_action = collection_action
24
+ @collection_record_action = collection_record_action
25
+ @record_action = record_action
26
+ @bulk_action = bulk_action
27
+ end
28
+
29
+ def collection_action?
30
+ @collection_action
31
+ end
32
+
33
+ def collection_record_action?
34
+ @collection_record_action
35
+ end
36
+
37
+ def record_action?
38
+ @record_action
39
+ end
40
+
41
+ def bulk_action?
42
+ @bulk_action
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class BasicAction < Plutonium::Core::Action
5
+ def initialize(*args, **kwargs)
6
+ kwargs.reverse_merge! action_options
7
+ super(*args, **kwargs)
8
+ end
9
+
10
+ private
11
+
12
+ def action_options = {}
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class Collection
5
+ delegate_missing_to :@collection
6
+
7
+ def initialize(collection = {})
8
+ @collection = collection
9
+ end
10
+
11
+ def permitted_for(policy)
12
+ Collection.new(@collection.select { |name, action| policy.send :"#{action.name}?" })
13
+ end
14
+
15
+ def collection_actions
16
+ Collection.new(@collection.select { |name, action| action.collection_action? })
17
+ end
18
+
19
+ def collection_record_actions
20
+ Collection.new(@collection.select { |name, action| action.collection_record_action? })
21
+ end
22
+
23
+ def record_actions
24
+ Collection.new(@collection.select { |name, action| action.record_action? })
25
+ end
26
+
27
+ def bulk_actions
28
+ Collection.new(@collection.select { |name, action| action.bulk_action? })
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class DestroyAction < BasicAction
5
+ private
6
+
7
+ def action_options
8
+ {
9
+ icon: "trash",
10
+ route_options: Plutonium::Core::Action::RouteOptions.new(method: :delete),
11
+ action_class: "danger",
12
+ confirmation: "Are you sure?",
13
+ turbo_frame: "_top",
14
+ collection_record_action: true,
15
+ record_action: true
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class EditAction < BasicAction
5
+ private
6
+
7
+ def action_options
8
+ {
9
+ icon: "pencil",
10
+ route_options: Plutonium::Core::Action::RouteOptions.new(action: :edit),
11
+ action_class: "warning",
12
+ collection_record_action: true,
13
+ record_action: true
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class InteractiveAction < Plutonium::Core::Action
5
+ include Plutonium::Core::Definers::InputDefiner
6
+
7
+ Context = Data.define :resource_class
8
+
9
+ attr_reader :interaction, :inline, :inputs
10
+
11
+ def initialize(name, *args, interaction:, **kwargs)
12
+ set_interaction interaction
13
+
14
+ kwargs[:route_options] ||= build_route_options name
15
+ kwargs.reverse_merge! action_options
16
+ super(name, *args, **kwargs)
17
+ end
18
+
19
+ def confirmation
20
+ super || (inline ? "#{label}?" : nil)
21
+ end
22
+
23
+ private
24
+
25
+ def resource_class = interaction
26
+
27
+ def action_options
28
+ {
29
+ # TODO: move these into config
30
+ collection_action: [:interactive_resource_collection_action,
31
+ :interactive_resource_recordless_action].include?(action_type),
32
+ collection_record_action: action_type == :interactive_resource_record_action,
33
+ record_action: action_type == :interactive_resource_record_action,
34
+ bulk_action: action_type == :interactive_resource_collection_action
35
+ }
36
+ end
37
+
38
+ def set_interaction(interaction)
39
+ @interaction = interaction
40
+ @inputs = defined_inputs_for(interaction.filters.keys - [:resource, :resources])
41
+ @inline = @inputs.blank? unless inline == false
42
+ end
43
+
44
+ def build_route_options(name)
45
+ method = inline ? :post : :get
46
+ action = action_type
47
+ options = {interactive_action: name}
48
+
49
+ RouteOptions.new action:, method:, options:
50
+ end
51
+
52
+ def action_type
53
+ if interaction.filters.key? :resource
54
+ :interactive_resource_record_action
55
+ elsif interaction.filters.key? :resources
56
+ :interactive_resource_collection_action
57
+ else
58
+ :interactive_resource_recordless_action
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class NewAction < BasicAction
5
+ private
6
+
7
+ def action_options
8
+ {
9
+ icon: "plus-lg",
10
+ route_options: Plutonium::Core::Action::RouteOptions.new(action: :new),
11
+ action_class: "primary",
12
+ collection_action: true
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ class ShowAction < BasicAction
5
+ private
6
+
7
+ def action_options
8
+ {
9
+ icon: "box-arrow-up-right",
10
+ action_class: "primary",
11
+ collection_record_action: true
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Plutonium
2
+ module Core
3
+ module Actions
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :BasicAction
8
+ autoload :Collection
9
+ autoload :NewAction
10
+ autoload :DestroyAction
11
+ autoload :EditAction
12
+ autoload :InteractiveAction
13
+ autoload :ShowAction
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,121 @@
1
+ module Plutonium
2
+ module Core
3
+ module AppController
4
+ extend ActiveSupport::Concern
5
+ include Plutonium::Core::Controllers::EntityScoping
6
+
7
+ included do
8
+ helper_method :current_parent
9
+ helper_method :adapt_route_args
10
+ end
11
+
12
+ private
13
+
14
+ def resource_presenter(resource_class)
15
+ presenter_class = "#{current_package}::#{resource_class}Presenter".constantize
16
+ presenter_class.new resource_context
17
+ end
18
+
19
+ def policy_namespace(scope)
20
+ [current_package.to_s.underscore.to_sym, scope]
21
+ end
22
+
23
+ # Menu Builder
24
+ def build_namespace_node(namespaces, resource, parent)
25
+ current = namespaces.shift
26
+ if namespaces.size.zero?
27
+ parent[current.pluralize] = url_for(adapt_route_args(resource, use_parent: false))
28
+ else
29
+ parent[current] = {}
30
+ build_namespace_node(namespaces, resource, parent[current])
31
+ end
32
+ # parent.sort!
33
+ end
34
+
35
+ def build_namespace_tree(resources)
36
+ root = {}
37
+ resources.each do |resource|
38
+ namespaces = resource.name.split("::")
39
+ build_namespace_node(namespaces, resource, root)
40
+ end
41
+ root
42
+ end
43
+
44
+ def build_sidebar_menu
45
+ build_namespace_tree(current_engine.resource_register)
46
+ end
47
+
48
+ # Menu Builder
49
+
50
+ def current_parent
51
+ return unless parent_route_param.present?
52
+
53
+ @current_parent ||= begin
54
+ parent_route_key = parent_route_param.to_s.gsub(/_id$/, "").to_sym
55
+ parent_class = current_engine.registered_resource_route_key_lookup[parent_route_key]
56
+ parent_scope = parent_class.from_path_param(params[parent_route_param])
57
+ parent_scope = parent_scope.associated_with(current_scoped_entity) if scoped_to_entity?
58
+ parent_scope.first!
59
+ end
60
+ end
61
+
62
+ def parent_route_param
63
+ @parent_route_param ||= request.path_parameters.keys.reverse.find { |key| /_id$/.match? key }
64
+ end
65
+
66
+ #
67
+ # Returns the attribute on the resource if there is a current parent and the resource has a belongs to association to it
68
+ #
69
+ def parent_input_param
70
+ return unless current_parent.present?
71
+
72
+ resource_class.reflect_on_all_associations(:belongs_to).find { |assoc| assoc.klass == current_parent.class }&.name&.to_sym
73
+ end
74
+
75
+ #
76
+ # Returns a dynamic list of args to be used with `url_for` which considers the route namespace and nesting.
77
+ # The current entity and parent record (for nested routes) are inserted appropriately, ensuring that generated urls
78
+ # obey the current routing.
79
+ #
80
+ # e.g. of route helpers that will be invoked given the output of this method
81
+ #
82
+ # - when invoked in a root route (/acme/dashboard/users)
83
+ #
84
+ # `adapt_route_args User` => `entity_users_*`
85
+ # `adapt_route_args @user` => `entity_user_*`
86
+ # `adapt_route_args @user, action: :edit` => `edit_entity_user_*`
87
+ # `adapt_route_args @user, Post => `entity_user_posts_*`
88
+ #
89
+ # - when invoked in a nested route (/acme/dashboard/users/1/post/1)
90
+ #
91
+ # `adapt_route_args Post` => `entity_user_posts_*`
92
+ # `adapt_route_args @post` => `entity_user_post_*`
93
+ # `adapt_route_args @post, action: :edit` => `edit_entity_user_post_*`
94
+ #
95
+ # @param [Class, ApplicationRecord] *args arguments you would normally pass to `url_for`
96
+ # @param [Symbol] action optional action to invoke e.g. :new, :edit
97
+ #
98
+ # @return [Array[Class, ApplicationRecord, Symbol]] args to pass to `url_for`
99
+ #
100
+ def adapt_route_args(*args, action: nil, use_parent: true, **kwargs)
101
+ # If the last item is a class and the action is :new e.g. `adapt_route_args User, action: :new`,
102
+ # it must be converted into a symbol to generate the appropriate helper i.e `new_user_*`
103
+ # to match the url helper generated by `resources :users`
104
+ resource = args.pop
105
+ resource = resource.model_name.singular_route_key.to_sym if action == :new && resource.is_a?(Class)
106
+ args.push resource
107
+
108
+ parent = use_parent ? current_parent : nil
109
+
110
+ base_args = if scoped_to_entity?
111
+ [action, current_scoped_entity.becomes(scoped_entity_class), parent]
112
+ else
113
+ [action, parent]
114
+ end
115
+
116
+ # rails compacts this list. no need to handle nils
117
+ base_args + args + [**kwargs]
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,15 @@
1
+ module Plutonium
2
+ module Core
3
+ module Autodiscovery
4
+ module Discoverer
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def resource_class
10
+ raise NotImplementedError, "#{self.class}#resource_class"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end