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