plutonium 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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