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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.standard.yml +4 -0
- data/.vscode/extensions.json +15 -0
- data/.vscode/launch.json +7 -0
- data/.vscode/settings.json +35 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README copy.md +84 -0
- data/README.md +67 -0
- data/Rakefile +8 -0
- data/app/views/layouts/resource.html.erb +43 -0
- data/app/views/resource/_color_modes.html.erb +55 -0
- data/app/views/resource/_details.html.erb +6 -0
- data/app/views/resource/_empty_card.html.erb +12 -0
- data/app/views/resource/_flash.html.erb +9 -0
- data/app/views/resource/_form.html.erb +32 -0
- data/app/views/resource/_header.html.erb +8 -0
- data/app/views/resource/_interactive_resource_action_form.html.erb +67 -0
- data/app/views/resource/_messages.html.erb +1 -0
- data/app/views/resource/_metric_card.html.erb +16 -0
- data/app/views/resource/_nav_user.html.erb +4 -0
- data/app/views/resource/_pagination.html.erb +6 -0
- data/app/views/resource/_pagy_pagination.html.erb +15 -0
- data/app/views/resource/_resource.html.erb +1 -0
- data/app/views/resource/_resource.rabl +5 -0
- data/app/views/resource/_sidebar.html.erb +11 -0
- data/app/views/resource/_sidebar_menu.html.erb +1 -0
- data/app/views/resource/_tab_menu.html.erb +13 -0
- data/app/views/resource/_table.html.erb +78 -0
- data/app/views/resource/_table_actions.html.erb +15 -0
- data/app/views/resource/_toast.html.erb +26 -0
- data/app/views/resource/_toolbar.html.erb +22 -0
- data/app/views/resource/_toolbar_actions.html.erb +16 -0
- data/app/views/resource/_toolbar_breadcrumbs.html.erb +32 -0
- data/app/views/resource/_toolbar_search_input.erb +27 -0
- data/app/views/resource/edit.html.erb +10 -0
- data/app/views/resource/errors.rabl +3 -0
- data/app/views/resource/index.html.erb +19 -0
- data/app/views/resource/index.rabl +3 -0
- data/app/views/resource/interactive_resource_collection_action.html.erb +11 -0
- data/app/views/resource/interactive_resource_record_action.html.erb +11 -0
- data/app/views/resource/interactive_resource_recordless_action.html.erb +11 -0
- data/app/views/resource/new.html.erb +11 -0
- data/app/views/resource/readme.md +16 -0
- data/app/views/resource/show.html.erb +14 -0
- data/app/views/resource/show.rabl +3 -0
- data/brakeman.ignore +51 -0
- data/lib/active_model/validations/array_validator.rb +74 -0
- data/lib/active_model/validations/attached_validator.rb +17 -0
- data/lib/active_model/validations/url_validator.rb +51 -0
- data/lib/generators/pu/core/install/install_generator.rb +43 -0
- data/lib/generators/pu/core/install/templates/.keep +0 -0
- data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/app/interactions/resource_interaction.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +5 -0
- data/lib/generators/pu/core/install/templates/app/policies/resource_policy.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +2 -0
- data/lib/generators/pu/core/install/templates/config/packages.rb +3 -0
- data/lib/generators/pu/gem/pagy/pagy_generator.rb +25 -0
- data/lib/generators/pu/gem/pagy/templates/.keep +0 -0
- data/lib/generators/pu/gem/pagy/templates/config/initializers/pagy.rb +4 -0
- data/lib/generators/pu/gem/rabl/rabl_generator.rb +25 -0
- data/lib/generators/pu/gem/rabl/templates/.keep +0 -0
- data/lib/generators/pu/gem/rabl/templates/config/initializers/rabl.rb +60 -0
- data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +25 -0
- data/lib/generators/pu/gem/simple_form/templates/.keep +0 -0
- data/lib/generators/pu/gen/pug/pug_generator.rb +43 -0
- data/lib/generators/pu/gen/pug/templates/pug.rb.tt +23 -0
- data/lib/generators/pu/pkg/app/app_generator.rb +60 -0
- data/lib/generators/pu/pkg/app/templates/app/controllers/resource_controller.rb.tt +26 -0
- data/lib/generators/pu/pkg/app/templates/app/interactions/resource_interaction.rb.tt +4 -0
- data/lib/generators/pu/pkg/app/templates/app/policies/resource_policy.rb.tt +4 -0
- data/lib/generators/pu/pkg/app/templates/app/presenters/resource_presenter.rb.tt +4 -0
- data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +17 -0
- data/lib/generators/pu/pkg/app/templates/lib/engine.rb.tt +14 -0
- data/lib/generators/pu/pkg/feature/feature_generator.rb +44 -0
- data/lib/generators/pu/pkg/feature/templates/.keep +0 -0
- data/lib/generators/pu/pkg/feature/templates/app/controllers/resource_controller.rb.tt +7 -0
- data/lib/generators/pu/pkg/feature/templates/app/interactions/resource_interaction.rb.tt +4 -0
- data/lib/generators/pu/pkg/feature/templates/app/models/resource_record.rb.tt +5 -0
- data/lib/generators/pu/pkg/feature/templates/app/policies/resource_policy.rb.tt +4 -0
- data/lib/generators/pu/pkg/feature/templates/app/presenters/resource_presenter.rb.tt +4 -0
- data/lib/generators/pu/pkg/feature/templates/lib/engine.rb.tt +8 -0
- data/lib/generators/pu/resource/conn/conn_generator.rb +54 -0
- data/lib/generators/pu/resource/conn/templates/.keep +0 -0
- data/lib/generators/pu/resource/conn/templates/app/controllers/resource_controller.rb.tt +3 -0
- data/lib/generators/pu/resource/conn/templates/app/policies/resource_policy.rb.tt +3 -0
- data/lib/generators/pu/resource/conn/templates/app/presenters/resource_presenter.rb.tt +3 -0
- data/lib/generators/pu/resource/model/USAGE +113 -0
- data/lib/generators/pu/resource/model/model_generator.rb +163 -0
- data/lib/generators/pu/resource/model/templates/controller.rb.tt +5 -0
- data/lib/generators/pu/resource/model/templates/create_table_migration.rb.tt +26 -0
- data/lib/generators/pu/resource/model/templates/model.rb.tt +53 -0
- data/lib/generators/pu/resource/model/templates/module.rb.tt +7 -0
- data/lib/generators/pu/resource/model/templates/policy.rb.tt +4 -0
- data/lib/generators/pu/resource/model/templates/presenter.rb.tt +4 -0
- data/lib/generators/pu/resource/scaffold/scaffold_generator.rb +219 -0
- data/lib/generators/pu/resource/scaffold/templates/app/controllers/admin_resources/resource_controller.rb.tt +7 -0
- data/lib/generators/pu/resource/scaffold/templates/app/controllers/entity_resources/resource_controller.rb.tt +7 -0
- data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/admin/resource_policy.rb.tt +22 -0
- data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/entity/resource_policy.rb.tt +22 -0
- data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/resource_policy.rb.tt +13 -0
- data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/admin_presenter.rb.tt +7 -0
- data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/entity_presenter.rb.tt +7 -0
- data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/presenter.rb.tt +23 -0
- data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.html.erb.tt +3 -0
- data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.rabl +7 -0
- data/lib/generators/pu/rodauth/account_generator.rb +120 -0
- data/lib/generators/pu/rodauth/concerns/account_selector.rb +22 -0
- data/lib/generators/pu/rodauth/concerns/configuration.rb +211 -0
- data/lib/generators/pu/rodauth/concerns/feature_selector.rb +125 -0
- data/lib/generators/pu/rodauth/install_generator.rb +69 -0
- data/lib/generators/pu/rodauth/migration/active_record/account_expiration.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/active_sessions.erb +7 -0
- data/lib/generators/pu/rodauth/migration/active_record/audit_logging.erb +16 -0
- data/lib/generators/pu/rodauth/migration/active_record/base.erb +22 -0
- data/lib/generators/pu/rodauth/migration/active_record/disallow_password_reuse.erb +5 -0
- data/lib/generators/pu/rodauth/migration/active_record/email_auth.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/jwt_refresh.erb +7 -0
- data/lib/generators/pu/rodauth/migration/active_record/lockout.erb +13 -0
- data/lib/generators/pu/rodauth/migration/active_record/otp.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/password_expiration.erb +6 -0
- data/lib/generators/pu/rodauth/migration/active_record/recovery_codes.erb +6 -0
- data/lib/generators/pu/rodauth/migration/active_record/remember.erb +7 -0
- data/lib/generators/pu/rodauth/migration/active_record/reset_password.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/separate_passwords.erb +5 -0
- data/lib/generators/pu/rodauth/migration/active_record/single_session.erb +6 -0
- data/lib/generators/pu/rodauth/migration/active_record/sms_codes.erb +9 -0
- data/lib/generators/pu/rodauth/migration/active_record/verify_account.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/verify_login_change.erb +8 -0
- data/lib/generators/pu/rodauth/migration/active_record/webauthn.erb +13 -0
- data/lib/generators/pu/rodauth/migration/sequel/account_expiration.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/active_sessions.erb +8 -0
- data/lib/generators/pu/rodauth/migration/sequel/audit_logging.erb +17 -0
- data/lib/generators/pu/rodauth/migration/sequel/base.erb +25 -0
- data/lib/generators/pu/rodauth/migration/sequel/disallow_password_reuse.erb +6 -0
- data/lib/generators/pu/rodauth/migration/sequel/email_auth.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/jwt_refresh.erb +8 -0
- data/lib/generators/pu/rodauth/migration/sequel/lockout.erb +11 -0
- data/lib/generators/pu/rodauth/migration/sequel/otp.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/password_expiration.erb +5 -0
- data/lib/generators/pu/rodauth/migration/sequel/recovery_codes.erb +6 -0
- data/lib/generators/pu/rodauth/migration/sequel/remember.erb +6 -0
- data/lib/generators/pu/rodauth/migration/sequel/reset_password.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/separate_passwords.erb +6 -0
- data/lib/generators/pu/rodauth/migration/sequel/single_session.erb +5 -0
- data/lib/generators/pu/rodauth/migration/sequel/sms_codes.erb +8 -0
- data/lib/generators/pu/rodauth/migration/sequel/verify_account.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/verify_login_change.erb +7 -0
- data/lib/generators/pu/rodauth/migration/sequel/webauthn.erb +13 -0
- data/lib/generators/pu/rodauth/migration_generator.rb +190 -0
- data/lib/generators/pu/rodauth/templates/INSTRUCTIONS +52 -0
- data/lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt +6 -0
- data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +3 -0
- data/lib/generators/pu/rodauth/templates/app/mailers/account_mailer.rb.tt +4 -0
- data/lib/generators/pu/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +62 -0
- data/lib/generators/pu/rodauth/templates/app/misc/account_rodauth_plugin.rb.tt +255 -0
- data/lib/generators/pu/rodauth/templates/app/misc/rodauth_app.rb.tt +24 -0
- data/lib/generators/pu/rodauth/templates/app/misc/rodauth_plugin.rb.tt +234 -0
- data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +40 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +7 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form.html.erb +26 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +6 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_login.html.erb +27 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_password.html.erb +27 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/close_account.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/confirm_password.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/create_account.html.erb +35 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/email_auth.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/login.html.erb +4 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/logout.html.erb +14 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +3 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_auth.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_disable.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_setup.html.erb +41 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/remember.html.erb +22 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password.html.erb +19 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_auth.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_disable.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_request.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_setup.html.erb +23 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_email_auth_request_form.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form.html.erb +24 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form_footer.html.erb +7 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/add_recovery_codes.html.erb +16 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_login.html.erb +25 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_password.html.erb +25 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/close_account.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/confirm_password.html.erb +19 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/create_account.html.erb +33 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/email_auth.html.erb +3 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/login.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/logout.html.erb +10 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/multi_phase_login.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_auth.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_disable.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_setup.html.erb +32 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_auth.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_codes.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/remember.html.erb +18 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password_request.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_auth.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_confirm.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_disable.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_request.html.erb +3 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_setup.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_auth.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_disable.html.erb +11 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_manage.html.erb +26 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account_request.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account.html.erb +19 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account_resend.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_login_change.html.erb +3 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_auth.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_autofill.html.erb +10 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_remove.html.erb +21 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_setup.html.erb +21 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +13 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +22 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +9 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account.html.erb +21 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +17 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +15 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +10 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +23 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +23 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/password_changed.text.erb +2 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password_notify.text.erb +2 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +5 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb +4 -0
- data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +10 -0
- data/lib/generators/pu/rodauth/templates/config/initializers/rodauth.rb.tt +3 -0
- data/lib/generators/pu/rodauth/templates/db/migrate/create_rodauth.rb.tt +13 -0
- data/lib/generators/pu/rodauth/views_generator.rb +125 -0
- data/lib/plutonium/auth/public_access.rb +17 -0
- data/lib/plutonium/auth/rodauth.rb +35 -0
- data/lib/plutonium/auth.rb +12 -0
- data/lib/plutonium/config.rb +11 -0
- data/lib/plutonium/core/.DS_Store +0 -0
- data/lib/plutonium/core/action.rb +46 -0
- data/lib/plutonium/core/actions/basic_action.rb +16 -0
- data/lib/plutonium/core/actions/collection.rb +33 -0
- data/lib/plutonium/core/actions/destroy_action.rb +21 -0
- data/lib/plutonium/core/actions/edit_action.rb +19 -0
- data/lib/plutonium/core/actions/interactive_action.rb +64 -0
- data/lib/plutonium/core/actions/new_action.rb +18 -0
- data/lib/plutonium/core/actions/show_action.rb +17 -0
- data/lib/plutonium/core/actions.rb +17 -0
- data/lib/plutonium/core/app_controller.rb +121 -0
- data/lib/plutonium/core/autodiscovery/discoverer.rb +15 -0
- data/lib/plutonium/core/autodiscovery/input_discoverer.rb +33 -0
- data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +33 -0
- data/lib/plutonium/core/autodiscovery.rb +13 -0
- data/lib/plutonium/core/controllers/authorizable.rb +56 -0
- data/lib/plutonium/core/controllers/bootable.rb +44 -0
- data/lib/plutonium/core/controllers/crud_actions.rb +128 -0
- data/lib/plutonium/core/controllers/entity_scoping.rb +69 -0
- data/lib/plutonium/core/controllers/interactive_actions.rb +210 -0
- data/lib/plutonium/core/controllers/presentable.rb +59 -0
- data/lib/plutonium/core/controllers.rb +16 -0
- data/lib/plutonium/core/definers/action_definer.rb +25 -0
- data/lib/plutonium/core/definers/field_definer.rb +19 -0
- data/lib/plutonium/core/definers/input_definer.rb +37 -0
- data/lib/plutonium/core/definers/renderer_definer.rb +35 -0
- data/lib/plutonium/core/definers.rb +14 -0
- data/lib/plutonium/core/fields/inputs/association_input.rb +26 -0
- data/lib/plutonium/core/fields/inputs/basic_input.rb +42 -0
- data/lib/plutonium/core/fields/inputs/belongs_to_input.rb +15 -0
- data/lib/plutonium/core/fields/inputs/factory.rb +58 -0
- data/lib/plutonium/core/fields/inputs/has_many_input.rb +15 -0
- data/lib/plutonium/core/fields/inputs/noop_input.rb +19 -0
- data/lib/plutonium/core/fields/inputs.rb +18 -0
- data/lib/plutonium/core/fields/renderers/association_renderer.rb +25 -0
- data/lib/plutonium/core/fields/renderers/basic_renderer.rb +27 -0
- data/lib/plutonium/core/fields/renderers/factory.rb +52 -0
- data/lib/plutonium/core/fields/renderers.rb +15 -0
- data/lib/plutonium/core/fields.rb +12 -0
- data/lib/plutonium/core/ui/collection.rb +14 -0
- data/lib/plutonium/core/ui/detail.rb +11 -0
- data/lib/plutonium/core/ui/form.rb +11 -0
- data/lib/plutonium/core/ui.rb +13 -0
- data/lib/plutonium/core.rb +16 -0
- data/lib/plutonium/helpers/action_buttons_helper.rb +32 -0
- data/lib/plutonium/helpers/application_helper.rb +22 -0
- data/lib/plutonium/helpers/attachment_helper.rb +62 -0
- data/lib/plutonium/helpers/content_helper.rb +66 -0
- data/lib/plutonium/helpers/display_helper.rb +83 -0
- data/lib/plutonium/helpers/form_helper.rb +24 -0
- data/lib/plutonium/helpers/menu_helper.rb +69 -0
- data/lib/plutonium/helpers/pagination_helper.rb +9 -0
- data/lib/plutonium/helpers/turbo_helper.rb +13 -0
- data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +9 -0
- data/lib/plutonium/helpers.rb +31 -0
- data/lib/plutonium/initializers/TODO +2 -0
- data/lib/plutonium/initializers/pagy.rb +5 -0
- data/lib/plutonium/initializers/patches.rb +2 -0
- data/lib/plutonium/initializers/rabl.rb +60 -0
- data/lib/plutonium/initializers/simple_form.rb +405 -0
- data/lib/plutonium/lib/after_commit.rb +34 -0
- data/lib/plutonium/lib/bit_flags.rb +36 -0
- data/lib/plutonium/packaging/app.rb +125 -0
- data/lib/plutonium/packaging/feature.rb +18 -0
- data/lib/plutonium/packaging/package.rb +22 -0
- data/lib/plutonium/packaging.rb +9 -0
- data/lib/plutonium/policy/initializer.rb +22 -0
- data/lib/plutonium/policy/scope.rb +19 -0
- data/lib/plutonium/policy.rb +8 -0
- data/lib/plutonium/preserved__/field.rb +65 -0
- data/lib/plutonium/preserved__/input.rb +93 -0
- data/lib/plutonium/reactor/core.rb +61 -0
- data/lib/plutonium/reactor/resource_context.rb +15 -0
- data/lib/plutonium/reactor/resource_controller.rb +108 -0
- data/lib/plutonium/reactor/resource_interaction.rb +8 -0
- data/lib/plutonium/reactor/resource_policy.rb +105 -0
- data/lib/plutonium/reactor/resource_presenter.rb +42 -0
- data/lib/plutonium/reactor/resource_record.rb +123 -0
- data/lib/plutonium/reactor.rb +13 -0
- data/lib/plutonium/refinements/parameter_refinements.rb +26 -0
- data/lib/plutonium/simple_form_components/attachment_component.rb +77 -0
- data/lib/plutonium/simple_form_components/input_group_component.rb +14 -0
- data/lib/plutonium/version.rb +3 -0
- data/lib/plutonium.rb +31 -0
- data/plutonium.gemspec +47 -0
- data/public/.keep +0 -0
- data/public/plutonium-assets/application.css +24280 -0
- data/public/plutonium-assets/application.js +31420 -0
- data/public/plutonium-assets/fonts/bootstrap-icons.woff +0 -0
- data/public/plutonium-assets/fonts/bootstrap-icons.woff2 +0 -0
- data/public/plutonium-assets/logo.png +0 -0
- data/sig/plutonium.rbs +4 -0
- metadata +519 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "pundit"
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module Policy
|
|
5
|
+
class Scope
|
|
6
|
+
include Plutonium::Policy::Initializer
|
|
7
|
+
|
|
8
|
+
def resolve
|
|
9
|
+
scope = context.resource_class.all
|
|
10
|
+
if @context.parent.present?
|
|
11
|
+
scope = scope.associated_with(@context.parent)
|
|
12
|
+
elsif @context.scope.present?
|
|
13
|
+
scope = scope.associated_with(@context.scope)
|
|
14
|
+
end
|
|
15
|
+
scope
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module UI
|
|
3
|
+
class Field
|
|
4
|
+
attr_reader :name, :label, :helper, :options
|
|
5
|
+
|
|
6
|
+
def initialize(name, **options)
|
|
7
|
+
@name = name
|
|
8
|
+
@label = options.delete :label
|
|
9
|
+
@helper = options.delete :helper
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def label
|
|
14
|
+
@label ||= name.to_s.titleize(keep_id_suffix: true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.build(name, type:, **options)
|
|
18
|
+
options[:helper] ||= case type
|
|
19
|
+
when :string, :text, :citext
|
|
20
|
+
:display_url_value if name.ends_with? "_url"
|
|
21
|
+
when :integer, :float, :decimal
|
|
22
|
+
:display_numeric_value
|
|
23
|
+
when :datetime, :timestamp, :time, :date
|
|
24
|
+
:display_datetime_value
|
|
25
|
+
when :boolean
|
|
26
|
+
:display_boolean_value
|
|
27
|
+
when :association
|
|
28
|
+
:display_association_value
|
|
29
|
+
when :attachment
|
|
30
|
+
:display_attachment_value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# binary: { name: "blob" },
|
|
34
|
+
# blob: { name: "blob" },
|
|
35
|
+
# json: { name: "json" },
|
|
36
|
+
|
|
37
|
+
options[:pu_max_width] ||= 400 if %i[string text citext].include? type
|
|
38
|
+
options[:pu_max_width] ||= 250
|
|
39
|
+
|
|
40
|
+
new name, **options
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.for_attribute(model_class, name, type: nil, **options)
|
|
44
|
+
association = attachment = nil
|
|
45
|
+
column = model_class.column_for_attribute name if model_class.respond_to? :column_for_attribute
|
|
46
|
+
if model_class.respond_to? :reflect_on_association
|
|
47
|
+
association = model_class.reflect_on_association name
|
|
48
|
+
attachment = model_class.reflect_on_association(:"#{name}_attachment") || model_class.reflect_on_association(:"#{name}_attachments")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if attachment.present?
|
|
52
|
+
type ||= :attachment
|
|
53
|
+
options[:stack_multiple] = false if options[:stack_multiple].nil?
|
|
54
|
+
elsif association.present?
|
|
55
|
+
type ||= :association if %i[belongs_to has_one].include? association.macro
|
|
56
|
+
elsif column.present?
|
|
57
|
+
type ||= column.type
|
|
58
|
+
options[:stack_multiple] = column.array? if options[:stack_multiple].nil? && column.respond_to?(:array?)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
build name, type:, **options
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module UI
|
|
3
|
+
class Input
|
|
4
|
+
attr_reader :name, :options
|
|
5
|
+
|
|
6
|
+
def initialize(name, **options)
|
|
7
|
+
@name = name
|
|
8
|
+
@options = options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.build(name, type:, **options)
|
|
12
|
+
multiple = options[:multiple]
|
|
13
|
+
|
|
14
|
+
definition = {}
|
|
15
|
+
case type
|
|
16
|
+
when :string, :text, :citext
|
|
17
|
+
definition = {
|
|
18
|
+
input_html: {
|
|
19
|
+
data: {controller: "textarea-autogrow"}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
when :datetime, :timestamp, :time, :date
|
|
23
|
+
definition = {
|
|
24
|
+
html5: false
|
|
25
|
+
}
|
|
26
|
+
when :slim_select
|
|
27
|
+
definition = {
|
|
28
|
+
wrapper: :slim_select,
|
|
29
|
+
input_html: {multiple:}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if multiple
|
|
33
|
+
placeholder = options[:placeholder] || "Select #{name.to_s.humanize(capitalize: false).pluralize}"
|
|
34
|
+
definition.deep_merge! input_html: {
|
|
35
|
+
data: {
|
|
36
|
+
slim_select_placeholder_value: placeholder,
|
|
37
|
+
slim_select_close_on_select_value: false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
placeholder = options[:placeholder] || "Select #{name.to_s.humanize(capitalize: false)}"
|
|
42
|
+
definition.deep_merge! include_blank: placeholder,
|
|
43
|
+
input_html: {
|
|
44
|
+
data: {slim_select_allow_deselect_value: true}
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
when :quill
|
|
48
|
+
definition = {wrapper: :quill}
|
|
49
|
+
when :money
|
|
50
|
+
currency = options.delete(:currency) || "$"
|
|
51
|
+
definition = {wrapper: :input_group, prepend: currency}
|
|
52
|
+
when :attachment
|
|
53
|
+
type = :file
|
|
54
|
+
definition = {
|
|
55
|
+
input_html: {multiple:},
|
|
56
|
+
attachment: true,
|
|
57
|
+
direct_upload: true
|
|
58
|
+
}
|
|
59
|
+
when :association
|
|
60
|
+
definition = {
|
|
61
|
+
as: :association
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
options = definition.deep_merge options
|
|
66
|
+
|
|
67
|
+
new name, **options
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.for_attribute(model_class, name, type: nil, **options)
|
|
71
|
+
column = model_class.column_for_attribute name if model_class.respond_to? :column_for_attribute
|
|
72
|
+
if model_class.respond_to? :reflect_on_association
|
|
73
|
+
attachment = model_class.reflect_on_association(:"#{name}_attachment") || model_class.reflect_on_association(:"#{name}_attachments")
|
|
74
|
+
association = model_class.reflect_on_association(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
type ||= :slim_select if options.key? :collection
|
|
78
|
+
|
|
79
|
+
if attachment.present?
|
|
80
|
+
type ||= :attachment
|
|
81
|
+
options[:multiple] = true if options[:multiple].nil? && attachment.macro == :has_many
|
|
82
|
+
elsif association.present?
|
|
83
|
+
type ||= :association
|
|
84
|
+
elsif column.present?
|
|
85
|
+
type ||= column.type
|
|
86
|
+
options[:multiple] = column.array? if options[:multiple].nil? && column.respond_to?(:array?)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
build name, type:, **options
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
|
2
|
+
# This is a glorified initializer
|
|
3
|
+
|
|
4
|
+
module Plutonium
|
|
5
|
+
module Reactor
|
|
6
|
+
class Core
|
|
7
|
+
def self.achieve_criticality!
|
|
8
|
+
Dir[Plutonium.lib_root.join("initializers", "**", "*.rb")].each do |file|
|
|
9
|
+
require file
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# setup a middleware to serve our assets
|
|
13
|
+
Rails.application.config.middleware.insert_before(
|
|
14
|
+
ActionDispatch::Static,
|
|
15
|
+
Rack::Static,
|
|
16
|
+
urls: ["/plutonium-assets"],
|
|
17
|
+
root: Plutonium.root.join("public"),
|
|
18
|
+
cascade: true
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
start_reloader!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.start_reloader!
|
|
25
|
+
return unless Plutonium::Config.reload_files
|
|
26
|
+
|
|
27
|
+
# GLORIOUS hot reloading!!!
|
|
28
|
+
@listener ||= begin
|
|
29
|
+
require "listen"
|
|
30
|
+
|
|
31
|
+
plutonium_lib_dir = Plutonium.lib_root.to_s
|
|
32
|
+
packages_dir = Rails.root.join("packages/").to_s
|
|
33
|
+
listener = Listen.to(plutonium_lib_dir, packages_dir, only: /\.rb$/) do |modified, added, removed|
|
|
34
|
+
(modified + added).each do |file|
|
|
35
|
+
if file.starts_with?(packages_dir)
|
|
36
|
+
# if package file was added, ignore it
|
|
37
|
+
# otherwise rails gets mad at us since engines cannot be loaded after initial boot
|
|
38
|
+
# TODO: check if guard has apis to control reloading dynamically
|
|
39
|
+
next if added.include? file
|
|
40
|
+
|
|
41
|
+
case File.basename(file)
|
|
42
|
+
when "engine.rb"
|
|
43
|
+
# reload engines. due to how we load packages, rails does not support
|
|
44
|
+
load file
|
|
45
|
+
# reload routes to pick up any registration changes
|
|
46
|
+
Rails.application.reload_routes!
|
|
47
|
+
else
|
|
48
|
+
# non engine package files are reloaded by rails automatically
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
load file
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
listener.start
|
|
56
|
+
listener
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Reactor
|
|
3
|
+
class ResourceContext
|
|
4
|
+
attr_reader :user, :resource_record, :resource_class, :parent, :scope
|
|
5
|
+
|
|
6
|
+
def initialize(user:, resource_record:, resource_class:, parent: nil, scope: nil)
|
|
7
|
+
@user = user
|
|
8
|
+
@resource_record = resource_record
|
|
9
|
+
@resource_class = resource_class || resource_record&.class
|
|
10
|
+
@parent = parent
|
|
11
|
+
@scope = scope
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require "action_controller"
|
|
2
|
+
require "pagy"
|
|
3
|
+
require "ransack"
|
|
4
|
+
|
|
5
|
+
require File.expand_path("refinements/parameter_refinements", Plutonium.lib_root)
|
|
6
|
+
using Plutonium::Refinements::ParameterRefinements
|
|
7
|
+
|
|
8
|
+
module Plutonium
|
|
9
|
+
module Reactor
|
|
10
|
+
class ResourceController < ActionController::Base
|
|
11
|
+
# remove this controller from the view lookup
|
|
12
|
+
# has the side effect of marking all public methods as private.
|
|
13
|
+
abstract!
|
|
14
|
+
|
|
15
|
+
include Pagy::Backend
|
|
16
|
+
include Plutonium::Core::Controllers::Bootable
|
|
17
|
+
include Plutonium::Core::Controllers::Authorizable
|
|
18
|
+
include Plutonium::Core::Controllers::Presentable
|
|
19
|
+
|
|
20
|
+
def self.inherited(child)
|
|
21
|
+
# Include our actions after we are inherited else they are marked as private due to our call to abstract!
|
|
22
|
+
child.send :include, Plutonium::Core::Controllers::CrudActions
|
|
23
|
+
child.send :include, Plutonium::Core::Controllers::InteractiveActions
|
|
24
|
+
|
|
25
|
+
# TODO: move this into interactive actions module
|
|
26
|
+
child.helper_method :current_interactive_action
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
add_flash_types :success, :warning, :error
|
|
31
|
+
append_view_path File.expand_path("app/views", Plutonium.root)
|
|
32
|
+
|
|
33
|
+
layout "resource"
|
|
34
|
+
helper Plutonium::Helpers
|
|
35
|
+
|
|
36
|
+
before_action :set_page_title
|
|
37
|
+
before_action :set_sidebar_menu
|
|
38
|
+
|
|
39
|
+
# https://github.com/ddnexus/pagy/blob/master/docs/extras/headers.md#headers
|
|
40
|
+
after_action { pagy_headers_merge(@pagy) if @pagy }
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# def current_layout
|
|
45
|
+
# send :_layout, lookup_context, []
|
|
46
|
+
# end
|
|
47
|
+
|
|
48
|
+
# Resource
|
|
49
|
+
|
|
50
|
+
def resource_record
|
|
51
|
+
@resource_record ||= (policy_scope(resource_class).from_path_param(params[:id]).first! if params[:id].present?)
|
|
52
|
+
end
|
|
53
|
+
helper_method :resource_record
|
|
54
|
+
|
|
55
|
+
def resource_params
|
|
56
|
+
# Example of documenting an ignore in the source code
|
|
57
|
+
# NOTE: Brakeman warning ignored for MassAssignment because inputs are filtered manually
|
|
58
|
+
input_params = params.require(resource_param_key).permit!.nilify.to_h
|
|
59
|
+
|
|
60
|
+
# Override any entity scoping params
|
|
61
|
+
input_params[scoped_entity_param_key] = current_scoped_entity if scoped_to_entity?
|
|
62
|
+
input_params[:"#{scoped_entity_param_key}_id"] = current_scoped_entity.id if scoped_to_entity?
|
|
63
|
+
# Override any parent params
|
|
64
|
+
input_params[parent_input_param] = current_parent if current_parent.present?
|
|
65
|
+
input_params[:"#{parent_input_param}_id"] = current_parent.id if current_parent.present?
|
|
66
|
+
|
|
67
|
+
current_presenter.defined_inputs_for(permitted_attributes)
|
|
68
|
+
.values.map { |input| input.collect input_params }
|
|
69
|
+
.reduce(:merge)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def resource_param_key
|
|
73
|
+
resource_class.model_name.singular_route_key
|
|
74
|
+
end
|
|
75
|
+
helper_method :resource_param_key
|
|
76
|
+
|
|
77
|
+
# Layout
|
|
78
|
+
|
|
79
|
+
def set_page_title
|
|
80
|
+
@page_title = "Pluton8"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def set_sidebar_menu
|
|
84
|
+
@sidebar_menu = build_sidebar_menu
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_sidebar_menu
|
|
88
|
+
raise NotImplementedError, "#{self.class}#build_sidebar_menu"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def resource_context
|
|
92
|
+
Plutonium::Reactor::ResourceContext.new(
|
|
93
|
+
user: current_user,
|
|
94
|
+
resource_class:,
|
|
95
|
+
resource_record: @resource_record,
|
|
96
|
+
parent: current_parent,
|
|
97
|
+
scope: scoped_to_entity? ? current_scoped_entity : nil
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
############
|
|
102
|
+
|
|
103
|
+
def current_package
|
|
104
|
+
@current_package ||= self.class.module_parents[-2]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Reactor
|
|
3
|
+
class ResourcePolicy
|
|
4
|
+
include Plutonium::Policy::Initializer
|
|
5
|
+
|
|
6
|
+
class Scope < Plutonium::Policy::Scope
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Core actions
|
|
10
|
+
|
|
11
|
+
def create?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def read?
|
|
16
|
+
true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update?
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def destroy?
|
|
24
|
+
true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Inferred actions
|
|
28
|
+
|
|
29
|
+
def index?
|
|
30
|
+
read?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def new?
|
|
34
|
+
create?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def show?
|
|
38
|
+
read?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def edit?
|
|
42
|
+
update?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Core attributes
|
|
46
|
+
|
|
47
|
+
def permitted_attributes_for_create
|
|
48
|
+
autodetect_fields_for :permitted_attributes_for_create
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def permitted_attributes_for_read
|
|
52
|
+
autodetect_fields_for :permitted_attributes_for_read
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def permitted_attributes_for_update
|
|
56
|
+
permitted_attributes_for_create
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Inferred attributes
|
|
60
|
+
|
|
61
|
+
def permitted_attributes_for_index
|
|
62
|
+
permitted_attributes_for_read
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def permitted_attributes_for_show
|
|
66
|
+
permitted_attributes_for_read
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def permitted_attributes_for_new
|
|
70
|
+
permitted_attributes_for_create
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def permitted_attributes_for_edit
|
|
74
|
+
permitted_attributes_for_update
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def permitted_associations
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def autodetect_fields_for(method_name)
|
|
84
|
+
maybe_warn_autodetect_usage method_name
|
|
85
|
+
|
|
86
|
+
context.resource_class.resource_field_names
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def maybe_warn_autodetect_usage(method)
|
|
90
|
+
raise "Resource field auto-detection: #{self.class}##{method} outside development" unless Rails.env.development?
|
|
91
|
+
|
|
92
|
+
Rails.logger.warn %(
|
|
93
|
+
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
|
94
|
+
|
|
95
|
+
Resource field auto-detection: #{self.class}##{method}
|
|
96
|
+
|
|
97
|
+
Auto-detected resource fields result in security holes and will fail outside of development.
|
|
98
|
+
Override #{context.resource_class}Policy or #{self.class} with your own ##{method} method.
|
|
99
|
+
|
|
100
|
+
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Reactor
|
|
3
|
+
class ResourcePresenter
|
|
4
|
+
include Plutonium::Core::Definers::FieldDefiner
|
|
5
|
+
include Plutonium::Core::Definers::ActionDefiner
|
|
6
|
+
|
|
7
|
+
def initialize(context)
|
|
8
|
+
@context = context
|
|
9
|
+
|
|
10
|
+
define_standard_actions
|
|
11
|
+
define_actions
|
|
12
|
+
define_fields
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
attr_reader :context
|
|
18
|
+
|
|
19
|
+
def define_fields
|
|
20
|
+
# override this in child presenters for custom field definitions
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def define_actions
|
|
24
|
+
# override this in child presenters for custom action definitions
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def define_standard_actions
|
|
28
|
+
define_action Plutonium::Core::Actions::NewAction.new(:new)
|
|
29
|
+
define_action Plutonium::Core::Actions::ShowAction.new(:show)
|
|
30
|
+
define_action Plutonium::Core::Actions::EditAction.new(:edit)
|
|
31
|
+
define_action Plutonium::Core::Actions::DestroyAction.new(:destroy)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# TODO: move this to its own definer
|
|
35
|
+
def define_interactive_action(name, interaction:, **)
|
|
36
|
+
define_action Plutonium::Core::Actions::InteractiveAction.new(name, interaction:, **)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def resource_class = context.resource_class
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Reactor
|
|
3
|
+
module ResourceRecord
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
scope :from_path_param, ->(param) { where(id: param) }
|
|
8
|
+
|
|
9
|
+
scope :associated_with, ->(record) do
|
|
10
|
+
named_scope = :"associated_with_#{record.model_name.singular}"
|
|
11
|
+
return send(named_scope, record) if respond_to?(named_scope)
|
|
12
|
+
|
|
13
|
+
# TODO: add logging
|
|
14
|
+
if (own_association = reflect_on_all_associations.find { |assoc| assoc.klass == record.class })
|
|
15
|
+
case own_association.macro
|
|
16
|
+
when :has_one
|
|
17
|
+
joins(own_association.name).where({
|
|
18
|
+
own_association.name.to_sym => {
|
|
19
|
+
record.class.primary_key => record.id
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
when :belongs_to
|
|
23
|
+
where(own_association.name => record)
|
|
24
|
+
when :has_many
|
|
25
|
+
joins(own_association.name).where(own_association.klass.table_name.to_sym => record)
|
|
26
|
+
else
|
|
27
|
+
raise Net::HTTPNotImplemented, "associated_with->##{own_association.macro}"
|
|
28
|
+
end
|
|
29
|
+
elsif (record_association = record.class.reflect_on_all_associations.find { |assoc| assoc.klass == klass })
|
|
30
|
+
# TODO: add a warning here about a potentially poor performing query
|
|
31
|
+
where(id: record.send(record_association.name))
|
|
32
|
+
else
|
|
33
|
+
raise "Could not resolve the association between '#{klass.name}' and '#{record.class.name}'\n\n" \
|
|
34
|
+
"Define\n" \
|
|
35
|
+
" 1. the associations between the models\n" \
|
|
36
|
+
" 2. a named scope e.g.\n\n" \
|
|
37
|
+
"scope :#{named_scope}, ->(#{record.model_name.singular}) { do_something_here }"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
# Path parameters
|
|
44
|
+
|
|
45
|
+
def path_parameter(param_name)
|
|
46
|
+
param_name = param_name.to_sym
|
|
47
|
+
|
|
48
|
+
scope :from_path_param, ->(param) { where(param_name => param) }
|
|
49
|
+
|
|
50
|
+
define_method :to_param do
|
|
51
|
+
return nil unless persisted?
|
|
52
|
+
|
|
53
|
+
send param_name
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def dynamic_path_parameter(param_name)
|
|
58
|
+
param_name = param_name.to_sym
|
|
59
|
+
|
|
60
|
+
scope :from_path_param, ->(param) { where(id: param.split("-").first) }
|
|
61
|
+
|
|
62
|
+
define_method :to_param do
|
|
63
|
+
return nil unless persisted?
|
|
64
|
+
|
|
65
|
+
"#{id}-#{send(param_name)}".parameterize
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Ransack
|
|
70
|
+
|
|
71
|
+
def ransackable_attributes(_auth_object = nil)
|
|
72
|
+
_ransackers.keys
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def ransackable_associations(_auth_object = nil)
|
|
76
|
+
[] # reflect_on_all_associations.map { |a| a.name.to_s }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def ransortable_attributes(auth_object = nil)
|
|
80
|
+
ransackable_attributes(auth_object) + %w[id created_at updated_at]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def ransackable_scopes(_auth_object = nil)
|
|
84
|
+
[]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def resource_field_names
|
|
88
|
+
@resource_field_names ||= belongs_to_association_field_names + has_one_association_field_names +
|
|
89
|
+
has_many_association_field_names + content_column_field_names
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def belongs_to_association_field_names
|
|
93
|
+
@belongs_to_association_field_names ||= reflect_on_all_associations(:belongs_to).map { |assoc| assoc.name.to_sym }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def has_one_association_field_names
|
|
97
|
+
@has_one_association_field_names ||= reflect_on_all_associations(:has_one).map { |assoc| assoc.name.to_sym }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def has_many_association_field_names
|
|
101
|
+
@has_many_association_field_names ||= reflect_on_all_associations(:has_many).map { |assoc| assoc.name.to_sym }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def content_column_field_names
|
|
105
|
+
@content_column_field_names ||= content_columns.map { |col| col.name.to_sym }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def has_many_association_routes
|
|
109
|
+
@has_many_association_routes ||= reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def to_label
|
|
114
|
+
%i[name title].each do |method|
|
|
115
|
+
name = send(method) if respond_to?(method)
|
|
116
|
+
return name if name.present?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
"#{model_name.human} ##{to_param}"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Reactor
|
|
3
|
+
extend ActiveSupport::Autoload
|
|
4
|
+
|
|
5
|
+
autoload :Core
|
|
6
|
+
autoload :ResourceContext
|
|
7
|
+
autoload :ResourceController
|
|
8
|
+
autoload :ResourceInteraction
|
|
9
|
+
autoload :ResourcePolicy
|
|
10
|
+
autoload :ResourcePresenter
|
|
11
|
+
autoload :ResourceRecord
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module Refinements
|
|
3
|
+
module ParameterRefinements
|
|
4
|
+
refine ActionController::Parameters do
|
|
5
|
+
def nilify
|
|
6
|
+
transform_values { |value| nilify_internal value }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def nilify_internal(value)
|
|
12
|
+
case value
|
|
13
|
+
when String
|
|
14
|
+
value.presence
|
|
15
|
+
when Hash
|
|
16
|
+
nilify value
|
|
17
|
+
when Array
|
|
18
|
+
value.map { |val| nilify_internal val }.compact
|
|
19
|
+
else
|
|
20
|
+
value
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|