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,33 @@
1
+ module Plutonium
2
+ module Core
3
+ module Autodiscovery
4
+ module InputDiscoverer
5
+ extend ActiveSupport::Concern
6
+ include Discoverer
7
+
8
+ class_methods do
9
+ private
10
+
11
+ def autodiscovery_input_cache = @autodiscovery_input_cache ||= {}
12
+ end
13
+
14
+ private
15
+
16
+ # If cache_discovery is enabled, use the class level cache that persists
17
+ # between requests, otherwise use the instance one.
18
+ def autodiscovery_input_cache
19
+ if Plutonium::Config.cache_discovery
20
+ self.class.autodiscovery_input_cache
21
+ else
22
+ @autodiscovery_input_cache ||= {}
23
+ end
24
+ end
25
+
26
+ def autodiscover_input(name)
27
+ autodiscovery_input_cache[name] ||=
28
+ Plutonium::Core::Fields::Inputs::Factory.for_resource_attribute(resource_class, name)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module Plutonium
2
+ module Core
3
+ module Autodiscovery
4
+ module RendererDiscoverer
5
+ extend ActiveSupport::Concern
6
+ include Discoverer
7
+
8
+ class_methods do
9
+ private
10
+
11
+ def autodiscovery_renderer_cache = @autodiscovery_renderer_cache ||= {}
12
+ end
13
+
14
+ private
15
+
16
+ # If cache_discovery is enabled, use the class level cache that persists
17
+ # between requests, otherwise use the instance one.
18
+ def autodiscovery_renderer_cache
19
+ if Plutonium::Config.cache_discovery
20
+ self.class.autodiscovery_renderer_cache
21
+ else
22
+ @autodiscovery_renderer_cache ||= {}
23
+ end
24
+ end
25
+
26
+ def autodiscover_renderer(name)
27
+ autodiscovery_renderer_cache[name] ||=
28
+ Plutonium::Core::Fields::Renderers::Factory.for_resource_attribute(resource_class, name)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Plutonium
2
+ module Core
3
+ module Autodiscovery
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :Discoverer
8
+ autoload :InputDiscoverer
9
+ autoload :RendererDiscoverer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ require "pundit"
2
+
3
+ module Plutonium
4
+ module Core
5
+ module Controllers
6
+ module Authorizable
7
+ extend ActiveSupport::Concern
8
+ include Pundit::Authorization
9
+
10
+ included do
11
+ after_action :verify_authorized
12
+ after_action :verify_policy_scoped, except: %i[new create]
13
+
14
+ helper_method :permitted_attributes
15
+ end
16
+
17
+ private
18
+
19
+ def policy_namespace(scope)
20
+ raise NotImplementedError, "policy_namespace"
21
+ end
22
+
23
+ def pundit_user
24
+ resource_context
25
+ end
26
+
27
+ def policy(scope)
28
+ super(policy_namespace(scope))
29
+ end
30
+
31
+ def policy_scope(scope)
32
+ super(policy_namespace(scope))
33
+ end
34
+
35
+ def authorize(record, query = nil)
36
+ super(policy_namespace(record), query)
37
+ end
38
+
39
+ def permitted_attributes
40
+ @permitted_attributes ||= current_policy.send :"permitted_attributes_for_#{action_name}"
41
+ end
42
+
43
+ def current_policy
44
+ @current_policy ||= begin
45
+ policy_subject = resource_record || resource_class
46
+ policy(policy_subject)
47
+ end
48
+ end
49
+
50
+ def parent_policy
51
+ @parent_policy ||= policy(current_parent) if current_parent.present?
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ module Bootable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class_attribute :package
9
+ class_attribute :resource_class, instance_writer: false, instance_predicate: false
10
+
11
+ helper_method :resource_class
12
+ end
13
+
14
+ class_methods do
15
+ def current_engine
16
+ "#{package}::Engine".constantize
17
+ end
18
+
19
+ private
20
+
21
+ def boot(package)
22
+ self.package = package
23
+
24
+ prepend_view_path current_engine.paths["app/views"].first
25
+ end
26
+
27
+ def controller_for(resource_class)
28
+ self.resource_class = resource_class
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def current_engine
35
+ @current_engine ||= self.class.current_engine
36
+ end
37
+
38
+ def current_package
39
+ self.class.package
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,128 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ module CrudActions
5
+ extend ActiveSupport::Concern
6
+
7
+ # GET /resources(.{format})
8
+ def index
9
+ authorize resource_class
10
+
11
+ @ransack = policy_scope(resource_class).ransack(params[:q])
12
+ @pagy, @resource_records = pagy @ransack.result
13
+ @collection = build_collection
14
+
15
+ render :index
16
+ end
17
+
18
+ # GET /resources/1(.{format})
19
+ def show
20
+ authorize resource_record
21
+
22
+ @detail = build_detail
23
+
24
+ render :show
25
+ end
26
+
27
+ # GET /resources/new
28
+ def new
29
+ authorize resource_class
30
+
31
+ @resource_record = resource_class.new
32
+ # set params if they have been passed
33
+ resource_record.attributes = params[resource_param_key].present? ? resource_params : {}
34
+ @form = build_form
35
+
36
+ render :new
37
+ end
38
+
39
+ # GET /resources/1/edit
40
+ def edit
41
+ authorize resource_record
42
+
43
+ # set params if they have been passed
44
+ resource_record.attributes = params[resource_param_key].present? ? resource_params : {}
45
+ @form = build_form
46
+
47
+ render :edit
48
+ end
49
+
50
+ # POST /resources(.{format})
51
+ def create
52
+ authorize resource_class
53
+
54
+ @resource_record = resource_class.new resource_params
55
+
56
+ respond_to do |format|
57
+ if resource_record.save
58
+ format.html do
59
+ redirect_to adapt_route_args(resource_record),
60
+ notice: "#{resource_class.model_name.human} was successfully created."
61
+ end
62
+ format.any { render :show, status: :created, location: adapt_route_args(resource_record) }
63
+ else
64
+ format.html do
65
+ @form = build_form
66
+ render :new, status: :unprocessable_entity
67
+ end
68
+ format.any do
69
+ @errors = resource_record.errors
70
+ render "errors", status: :unprocessable_entity
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ # PATCH/PUT /resources/1(.{format})
77
+ def update
78
+ authorize resource_record
79
+
80
+ respond_to do |format|
81
+ if resource_record.update(resource_params)
82
+ format.html do
83
+ redirect_to adapt_route_args(resource_record), notice: "#{resource_class.model_name.human} was successfully updated.",
84
+ status: :see_other
85
+ end
86
+ format.any { render :show, status: :ok, location: adapt_route_args(resource_record) }
87
+ else
88
+ format.html do
89
+ @form = build_form
90
+ render :edit, status: :unprocessable_entity
91
+ end
92
+ format.any do
93
+ @errors = resource_record.errors
94
+ render "errors", status: :unprocessable_entity
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # DELETE /resources/1(.{format})
101
+ def destroy
102
+ authorize resource_record
103
+
104
+ respond_to do |format|
105
+ resource_record.destroy
106
+
107
+ format.html do
108
+ redirect_to adapt_route_args(resource_class),
109
+ notice: "#{resource_class.model_name.human} was successfully deleted."
110
+ end
111
+ format.json { head :no_content }
112
+ rescue ActiveRecord::InvalidForeignKey
113
+ format.html do
114
+ redirect_to adapt_route_args(resource_record),
115
+ alert: "#{resource_class.model_name.human} is referenced by other records."
116
+ end
117
+ format.any do
118
+ @errors = ActiveModel::Errors.new resource_record
119
+ @errors.add :base, :existing_references, message: "is referenced by other records"
120
+
121
+ render "errors", status: :unprocessable_entity
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,69 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ module EntityScoping
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action :remember_scoped_entity
9
+ helper_method :current_scoped_entity
10
+ end
11
+
12
+ private
13
+
14
+ def scoped_to_entity?
15
+ current_engine.scoped_to_entity?
16
+ end
17
+
18
+ def scoped_entity_class
19
+ ensure_legal_entity_scoping_method_access! :scoped_entity_class
20
+
21
+ current_engine.scoped_entity_class
22
+ end
23
+
24
+ def scoped_entity_param_key
25
+ ensure_legal_entity_scoping_method_access! :scoped_entity_param_key
26
+
27
+ current_engine.scoped_entity_param_key
28
+ end
29
+
30
+ def scoped_entity_session_key
31
+ ensure_legal_entity_scoping_method_access! :scoped_entity_session_key
32
+
33
+ :scoped_entity_id
34
+ end
35
+
36
+ def current_scoped_entity
37
+ ensure_legal_entity_scoping_method_access! :current_scoped_entity
38
+
39
+ return unless current_user.present?
40
+
41
+ @current_scoped_entity ||= scoped_entity_class
42
+ .associated_with(current_user)
43
+ .from_path_param(request.path_parameters[scoped_entity_param_key])
44
+ .first! # Raise NotFound if user does not have access to the entity or it does not exist
45
+ end
46
+
47
+ def remember_scoped_entity
48
+ return unless scoped_to_entity?
49
+
50
+ session[scoped_entity_session_key] = current_scoped_entity.to_global_id.to_s
51
+ end
52
+
53
+ def remembered_scoped_entity
54
+ ensure_legal_entity_scoping_method_access! :remembered_scoped_entity
55
+
56
+ @remembered_scoped_entity ||= GlobalID::Locator.locate session[scoped_entity_session_key]
57
+ end
58
+
59
+ def ensure_legal_entity_scoping_method_access!(method)
60
+ return if scoped_to_entity?
61
+
62
+ raise NotImplementedError, "this request is not scoped to an entity\n\n" \
63
+ "add the `scope_to_entity YourEntityRecord` directive in " \
64
+ "#{current_engine} or implement #{self.class}##{method}"
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,210 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ module InteractiveActions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action :validate_interactive_resource_action, only: %i[
9
+ begin_interactive_resource_record_action commit_interactive_resource_record_action
10
+ begin_interactive_resource_collection_action commit_interactive_resource_collection_action
11
+ begin_interactive_resource_recordless_action commit_interactive_resource_recordless_action
12
+ ]
13
+
14
+ before_action :authorize_interactive_resource_record_action, only: %i[
15
+ begin_interactive_resource_record_action commit_interactive_resource_record_action
16
+ ]
17
+
18
+ before_action :authorize_interactive_resource_action, only: %i[
19
+ begin_interactive_resource_collection_action commit_interactive_resource_collection_action
20
+ begin_interactive_resource_recordless_action commit_interactive_resource_recordless_action
21
+ ]
22
+ end
23
+
24
+ # GET /resources/1/actions/:interactive_action
25
+ def begin_interactive_resource_record_action
26
+ @interaction = current_interactive_action.interaction.new interaction_params
27
+
28
+ if helpers.current_turbo_frame == "modal"
29
+ render layout: false
30
+ else
31
+ render :interactive_resource_record_action
32
+ end
33
+ end
34
+
35
+ # POST /resources/1/actions/:interactive_action
36
+ def commit_interactive_resource_record_action
37
+ respond_to do |format|
38
+ inputs = interaction_params.merge(resource: resource_record)
39
+ @interaction = current_interactive_action.interaction.run(inputs)
40
+
41
+ if @interaction.valid?
42
+ flash[:notice] = "TODO:#{current_interactive_action} was successfully updated."
43
+
44
+ format.html { redirect_to adapt_route_args(@interaction.result), status: :see_other }
45
+ format.any { render :show, status: :ok, location: adapt_route_args(@interaction.result) }
46
+
47
+ if helpers.current_turbo_frame == "modal"
48
+ format.turbo_stream do
49
+ render turbo_stream: [
50
+ turbo_stream.redirect(url_for(adapt_route_args(@interaction.result)))
51
+ ]
52
+ end
53
+ end
54
+ else
55
+ format.html do
56
+ render :interactive_resource_record_action, status: :unprocessable_entity
57
+ end
58
+ format.any do
59
+ @errors = @interaction.errors
60
+ render "errors", status: :unprocessable_entity
61
+ end
62
+
63
+ if helpers.current_turbo_frame == "modal"
64
+ format.turbo_stream do
65
+ render turbo_stream: turbo_stream.replace(:modal, partial: "interactive_resource_record_action_form")
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # GET /resources/actions/:interactive_action?ids[]=1&ids[]=2
73
+ def begin_interactive_resource_collection_action
74
+ # TODO: ensure that the selected list matches the returned value
75
+ interactive_resource_collection
76
+ @interaction = current_interactive_action.interaction.new((params[:interaction] || {}).except(:resources))
77
+
78
+ if helpers.current_turbo_frame == "modal"
79
+ render layout: false
80
+ else
81
+ render :interactive_resource_collection_action
82
+ end
83
+ end
84
+
85
+ # POST /resources/actions/:interactive_action?ids[]=1&ids[]=2
86
+ def commit_interactive_resource_collection_action
87
+ respond_to do |format|
88
+ inputs = interaction_params.merge(resources: interactive_resource_collection)
89
+ @interaction = current_interactive_action.interaction.run(inputs)
90
+
91
+ if @interaction.valid?
92
+ collection_count = interactive_resource_collection.size
93
+
94
+ flash[:notice] = "TODO:#{current_interactive_action} #{collection_count} #{resource_class.model_name.human.pluralize(collection_count)} successfully updated."
95
+
96
+ format.html { redirect_to adapt_route_args(resource_class) }
97
+ if helpers.current_turbo_frame == "modal"
98
+ format.turbo_stream do
99
+ render turbo_stream: [
100
+ turbo_stream.redirect(url_for(resource_class))
101
+ ]
102
+ end
103
+ end
104
+ else
105
+ format.html do
106
+ render :interactive_resource_collection_action, status: :unprocessable_entity
107
+ end
108
+ format.any do
109
+ @errors = @interaction.errors
110
+ render "errors", status: :unprocessable_entity
111
+ end
112
+
113
+ if helpers.current_turbo_frame == "modal"
114
+ format.turbo_stream do
115
+ render turbo_stream: turbo_stream.replace(:modal, partial: "interactive_resource_collection_action_form")
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ # GET /resources/actions/:interactive_action
123
+ def begin_interactive_resource_recordless_action
124
+ skip_policy_scope
125
+
126
+ @interaction = current_interactive_action.interaction.new interaction_params
127
+
128
+ if helpers.current_turbo_frame == "modal"
129
+ render layout: false
130
+ else
131
+ render :interactive_resource_recordless_action
132
+ end
133
+ end
134
+
135
+ # POST /resources/actions/:interactive_action
136
+ def commit_interactive_resource_recordless_action
137
+ skip_policy_scope
138
+
139
+ respond_to do |format|
140
+ inputs = interaction_params
141
+ @interaction = current_interactive_action.interaction.run(inputs)
142
+
143
+ if @interaction.valid?
144
+ flash[:notice] = "TODO:#{current_interactive_action} was successfully updated."
145
+
146
+ format.html { redirect_to adapt_route_args(resource_class) }
147
+
148
+ if helpers.current_turbo_frame == "modal"
149
+ format.turbo_stream do
150
+ render turbo_stream: [
151
+ turbo_stream.redirect(url_for(adapt_route_args(resource_class)))
152
+ ]
153
+ end
154
+ end
155
+ else
156
+ format.html do
157
+ render :interactive_resource_recordless_action, status: :unprocessable_entity
158
+ end
159
+ format.any do
160
+ @errors = @interaction.errors
161
+ render "errors", status: :unprocessable_entity
162
+ end
163
+
164
+ if helpers.current_turbo_frame == "modal"
165
+ format.turbo_stream do
166
+ render turbo_stream: turbo_stream.replace(:modal, partial: "interactive_resource_recordless_action_form")
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ def current_interactive_action
176
+ @current_interactive_action = interactive_resource_actions[params[:interactive_action].to_sym]
177
+ end
178
+
179
+ def interactive_resource_actions
180
+ @interactive_resource_actions ||= current_presenter.actions.except :new, :show, :edit, :destroy
181
+ end
182
+
183
+ def validate_interactive_resource_action
184
+ interactive_resource_action = params[:interactive_action]&.to_sym
185
+ unless interactive_resource_actions.key?(interactive_resource_action)
186
+ raise ::AbstractController::ActionNotFound, "Unknown action '#{interactive_resource_action}'"
187
+ end
188
+ end
189
+
190
+ def authorize_interactive_resource_record_action
191
+ interactive_resource_action = params[:interactive_action]&.to_sym
192
+ authorize resource_record, :"#{interactive_resource_action}?"
193
+ end
194
+
195
+ def authorize_interactive_resource_action
196
+ interactive_resource_action = params[:interactive_action]&.to_sym
197
+ authorize resource_class, :"#{interactive_resource_action}?"
198
+ end
199
+
200
+ def interactive_resource_collection
201
+ @interactive_resource_collection ||= policy_scope(resource_class).from_path_param(params.require(:ids)).all
202
+ end
203
+
204
+ def interaction_params
205
+ (params[:interaction] || {}).except(:resource, :resources)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,59 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ module Presentable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ helper_method :presentable_attributes
9
+ end
10
+
11
+ private
12
+
13
+ def resource_presenter(resource_class)
14
+ raise NotImplementedError, "#{self.class}#resource_presenter"
15
+ end
16
+
17
+ def current_presenter
18
+ resource_presenter resource_class
19
+ end
20
+
21
+ def presentable_attributes
22
+ @presentable_attributes ||= begin
23
+ presentable_attributes = permitted_attributes
24
+ presentable_attributes -= [scoped_entity_param_key, :"#{scoped_entity_param_key}_id"] if scoped_to_entity?
25
+ presentable_attributes -= [parent_input_param, :"#{parent_input_param}_id"] if current_parent.present?
26
+ presentable_attributes
27
+ end
28
+ end
29
+
30
+ def build_collection
31
+ Plutonium::Core::UI::Collection.new(
32
+ resource_class:,
33
+ records: @resource_records,
34
+ fields: current_presenter.defined_renderers_for(presentable_attributes),
35
+ actions: current_presenter.actions,
36
+ pagination: @pagy,
37
+ search_object: @ransack
38
+ )
39
+ end
40
+
41
+ def build_detail
42
+ Plutonium::Core::UI::Detail.new(
43
+ resource_class:,
44
+ record: resource_record,
45
+ fields: current_presenter.defined_renderers_for(presentable_attributes),
46
+ actions: current_presenter.actions
47
+ )
48
+ end
49
+
50
+ def build_form
51
+ Plutonium::Core::UI::Form.new(
52
+ record: resource_record,
53
+ inputs: current_presenter.defined_inputs_for(presentable_attributes)
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,16 @@
1
+ module Plutonium
2
+ module Core
3
+ module Controllers
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :Authorizable
8
+ autoload :Bootable
9
+ autoload :CrudActions
10
+ autoload :EntityScoping
11
+ autoload :Presentable
12
+ autoload :InteractiveActions
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ module ActionDefiner
5
+ extend ActiveSupport::Concern
6
+
7
+ def actions
8
+ action_definitions
9
+ end
10
+
11
+ private
12
+
13
+ def action_definitions = @action_definitions ||= Plutonium::Core::Actions::Collection.new
14
+
15
+ def define_action(action)
16
+ action_definitions[action.name] = action
17
+ end
18
+
19
+ def action_defined?(name)
20
+ action_definitions.key? name
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end