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,78 @@
|
|
1
|
+
<%
|
2
|
+
# locals: {
|
3
|
+
# table: "instance of Plutonium::UI::Builder::Collection"
|
4
|
+
# }
|
5
|
+
|
6
|
+
resource_class = table.resource_class
|
7
|
+
resources = table.records.to_a
|
8
|
+
record_actions = table.actions.collection_record_actions
|
9
|
+
search_object = table.search_object
|
10
|
+
%>
|
11
|
+
<div class="row">
|
12
|
+
<% unless resources.any? %>
|
13
|
+
<div class="col-12">
|
14
|
+
<%=
|
15
|
+
render 'empty_card', message: "You have no #{resource_name_plural(resource_class).downcase}" do
|
16
|
+
if policy(resource_class).create?
|
17
|
+
link_to "Create #{resource_name(resource_class)}", adapt_route_args(resource_class, action: :new), class: 'btn btn-outline-primary'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
%>
|
21
|
+
</div>
|
22
|
+
<% else %>
|
23
|
+
<div id="table-container" class="col-12 table-responsive max-vh-75 pb-2" data-controller="scroll-preserver" data-action="scroll->scroll-preserver#scrolled" >
|
24
|
+
<table class="table table-hover table-striped my-0">
|
25
|
+
<thead class="sticky-top">
|
26
|
+
<tr>
|
27
|
+
<th scope="col" class="text-center resource-table-col-id"><%= sort_link(search_object, :id, '#', class: "text-decoration-none") %></th>
|
28
|
+
<% table.fields.each do |name, field| %>
|
29
|
+
<th scope="col" class="resource-table-col-attr">
|
30
|
+
<% if resource_class.ransortable_attributes.include? name.to_s %>
|
31
|
+
<%= sort_link(search_object, name, field.label, class: "text-decoration-none") %>
|
32
|
+
<% else %>
|
33
|
+
<%= field.label %>
|
34
|
+
<% end %>
|
35
|
+
</th>
|
36
|
+
<% end %>
|
37
|
+
<th scope="col" class="text-center resource-table-col-actions">Actions</th>
|
38
|
+
</tr>
|
39
|
+
</thead>
|
40
|
+
<tbody>
|
41
|
+
<% resources.each do |resource| %>
|
42
|
+
<tr class="align-middle">
|
43
|
+
<td class="text-center text-truncate resource-table-cell-id">
|
44
|
+
<% if policy(resource).show? %>
|
45
|
+
<%= link_to resource.to_param, adapt_route_args(resource), class: "text-decoration-none" %>
|
46
|
+
<% else %>
|
47
|
+
<%= resource.to_param %>
|
48
|
+
<% end %>
|
49
|
+
</td>
|
50
|
+
<% table.fields.each do |name, field| %>
|
51
|
+
<%
|
52
|
+
options = field.options
|
53
|
+
max_width = options.delete :pu_max_width
|
54
|
+
%>
|
55
|
+
<td class='text-truncate resource-table-cell-attr' style="max-width: <%= max_width %>px;">
|
56
|
+
<%= field.render self, resource %>
|
57
|
+
</td>
|
58
|
+
<% end %>
|
59
|
+
<td class="text-center resource-table-cell-actions">
|
60
|
+
<%=
|
61
|
+
render partial: 'table_actions', locals: {
|
62
|
+
actions: record_actions.permitted_for(policy(resource)),
|
63
|
+
resource: resource
|
64
|
+
}
|
65
|
+
%>
|
66
|
+
</td>
|
67
|
+
</tr>
|
68
|
+
<% end %>
|
69
|
+
</tbody>
|
70
|
+
</table>
|
71
|
+
</div>
|
72
|
+
<% if table.pagination.present? %>
|
73
|
+
<div class="col-12">
|
74
|
+
<%= render 'pagination', pagination: table.pagination %>
|
75
|
+
</div>
|
76
|
+
<% end %>
|
77
|
+
<% end %>
|
78
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%
|
2
|
+
# locals: {
|
3
|
+
# resource: "the resource to generate actions for",
|
4
|
+
# actions: "list of actions to generate",
|
5
|
+
# }
|
6
|
+
%>
|
7
|
+
<% actions.values.each do |action| %>
|
8
|
+
<%=
|
9
|
+
table_action_button adapt_route_args(resource, action: action.route_options.action, **action.route_options.options),
|
10
|
+
icon: action.icon,
|
11
|
+
button_class: action.action_class,
|
12
|
+
method: action.route_options.method,
|
13
|
+
confirm: action.confirmation
|
14
|
+
%>
|
15
|
+
<% end %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<div aria-live="polite" aria-atomic="true" class="position-relative" data-controller="toasts">
|
2
|
+
<div class="toast-container top-0 end-0 p-3 ">
|
3
|
+
<% flash.each do |type, msg| %>
|
4
|
+
<%
|
5
|
+
type = { alert: :danger, error: :danger, warning: :warning, success: :success }[type.to_sym] || :primary
|
6
|
+
title = { danger: 'Error', warning: 'Warning', success: 'Success' }[type] || 'Info'
|
7
|
+
icon = {
|
8
|
+
danger: 'exclamation-triangle-fill',
|
9
|
+
warning: 'exclamation-diamond',
|
10
|
+
success: 'check-circle-fill'
|
11
|
+
}[type] || 'exclamation-circle'
|
12
|
+
%>
|
13
|
+
<div class="toast text-bg-<%= type %>" role="alert" aria-live="assertive" aria-atomic="true" data-turbo-temporary>
|
14
|
+
<div class="toast-header">
|
15
|
+
<i class="bi bi-<%= icon %>"></i>
|
16
|
+
<strong class="me-auto"><%= title %></strong>
|
17
|
+
<small class="text-body-secondary"><%= timeago(DateTime.now) %></small>
|
18
|
+
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
19
|
+
</div>
|
20
|
+
<div class="toast-body">
|
21
|
+
<%= msg %>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%
|
2
|
+
# locals: {
|
3
|
+
# parent?: "parent of the resource to render toolbar for",
|
4
|
+
# resource?: "resource to render toolbar for",
|
5
|
+
# resource_class: "Class of resource being rendered",
|
6
|
+
# }
|
7
|
+
|
8
|
+
resource = nil unless local_assigns[:resource].present?
|
9
|
+
associations = nil unless local_assigns[:associations].present?
|
10
|
+
%>
|
11
|
+
<div class="row justify-content-between py-2 mb-3 border-bottom">
|
12
|
+
<div class="col-sm-6">
|
13
|
+
<%= render partial: 'toolbar_breadcrumbs', locals: {
|
14
|
+
resource: resource,
|
15
|
+
resource_class: resource_class,
|
16
|
+
parent: parent
|
17
|
+
} %>
|
18
|
+
</div>
|
19
|
+
<div class="col-sm-6 text-end">
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%
|
2
|
+
# locals: {
|
3
|
+
# resource: "the resource to generate actions for",
|
4
|
+
# actions: "list of actions to generate",
|
5
|
+
# }
|
6
|
+
%>
|
7
|
+
<% actions.values.each do |action| %>
|
8
|
+
<%=
|
9
|
+
toolbar_action_button adapt_route_args(resource, action: action.route_options.action, **action.route_options.options),
|
10
|
+
icon: action.icon,
|
11
|
+
button_class: action.action_class,
|
12
|
+
method: action.route_options.method,
|
13
|
+
confirm: action.confirmation,
|
14
|
+
turbo_frame: action.turbo_frame
|
15
|
+
%>
|
16
|
+
<% end %>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%#
|
2
|
+
locals: {
|
3
|
+
parent?: "parent of the resource to render toolbar for",
|
4
|
+
resource?: "resource to render toolbar for",
|
5
|
+
resource_class: "Class of resource being rendered",
|
6
|
+
}
|
7
|
+
%>
|
8
|
+
<nav aria-label="breadcrumb" style="--bs-breadcrumb-divider: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M2.5 0L1 1.5 3.5 4 1 6.5 2.5 8l4-4-4-4z' fill='%236c757d'/%3E%3C/svg%3E");">
|
9
|
+
<ol class="breadcrumb my-1">
|
10
|
+
<% if parent.present? %>
|
11
|
+
<li class="breadcrumb-item"><%= link_to resource_name_plural(parent.class), adapt_route_args(parent.class, use_parent: false), class: 'text-decoration-none' %></li>
|
12
|
+
<li class="breadcrumb-item"><%= link_to display_name_of(parent), adapt_route_args(parent, use_parent: false), class: 'text-decoration-none' %></li>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<% if resource.present? %>
|
16
|
+
<li class="breadcrumb-item"><%= link_to resource_name_plural(resource_class), adapt_route_args(resource_class), class: 'text-decoration-none' %></li>
|
17
|
+
<% if /edit|update|.*interactive_resource.*/.match? action_name %>
|
18
|
+
<li class="breadcrumb-item"><%= link_to display_name_of(resource), adapt_route_args(resource), class: 'text-decoration-none' %></li>
|
19
|
+
<li class="breadcrumb-item active" aria-current="page"><%= (params[:interactive_action] || 'Edit').titleize %></li>
|
20
|
+
<% else %>
|
21
|
+
<li class="breadcrumb-item active" aria-current="page"><%= resource.persisted? ? display_name_of(resource) : 'New' %></li>
|
22
|
+
<% end %>
|
23
|
+
<% else %>
|
24
|
+
<% if /.*interactive_resource.*/.match? action_name %>
|
25
|
+
<li class="breadcrumb-item"><%= link_to resource_name_plural(resource_class), adapt_route_args(resource_class), class: 'text-decoration-none' %></li>
|
26
|
+
<li class="breadcrumb-item active" aria-current="page"><%= params[:interactive_action].titleize %></li>
|
27
|
+
<% else %>
|
28
|
+
<li class="breadcrumb-item"><%= resource_name_plural(resource_class) %></li>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
</ol>
|
32
|
+
</nav>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%
|
2
|
+
# locals: {
|
3
|
+
# search_object: "the object to build the search form for",
|
4
|
+
# search_field: "search input field name",
|
5
|
+
# }
|
6
|
+
%>
|
7
|
+
<%= search_form_for adapt_route_args(search_object), class: "d-inline", html: { data: { controller: "form", turbo_frame: nil } } do |f| %>
|
8
|
+
<label for="search" class="visually-hidden">Search</label>
|
9
|
+
<% if search_field.present? %>
|
10
|
+
<%=
|
11
|
+
f.search_field search_field, id: "search",
|
12
|
+
class: "form-control form-control-sm d-inline w-auto",
|
13
|
+
# since ransack trims strings, we instead
|
14
|
+
# use the url param because it preserves trailing spaces
|
15
|
+
# that way, when the frame reloads the user gets to continue typing
|
16
|
+
value: params[:q].try(:[], search_field),
|
17
|
+
placeholder: "search...",
|
18
|
+
data: {
|
19
|
+
action: "form#submit",
|
20
|
+
form_target: "focus"
|
21
|
+
}
|
22
|
+
|
23
|
+
%>
|
24
|
+
<% end %>
|
25
|
+
<%# preserve sorting %>
|
26
|
+
<%= f.hidden_field :s, value: params[:q].try(:[], :s) %>
|
27
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<% content_for :toolbar do %>
|
2
|
+
<%= render 'toolbar', resource_class: resource_class,
|
3
|
+
parent: current_parent do %>
|
4
|
+
<%=
|
5
|
+
render partial: 'toolbar_search_input', locals: {
|
6
|
+
search_object: @collection.search_object,
|
7
|
+
search_field: nil
|
8
|
+
}
|
9
|
+
%>
|
10
|
+
<%=
|
11
|
+
render partial: 'toolbar_actions', locals: {
|
12
|
+
actions: @collection.actions.collection_actions.permitted_for(policy(resource_class)),
|
13
|
+
resource: resource_class
|
14
|
+
}
|
15
|
+
%>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<%= render 'table', table: @collection %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% content_for :toolbar do %>
|
2
|
+
<%=
|
3
|
+
render partial: 'toolbar', locals: {
|
4
|
+
resource_class: resource_class,
|
5
|
+
resource: resource_record,
|
6
|
+
parent: current_parent,
|
7
|
+
}
|
8
|
+
%>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= render "interactive_resource_action_form", interactive_action: current_interactive_action %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% content_for :toolbar do %>
|
2
|
+
<%=
|
3
|
+
render partial: 'toolbar', locals: {
|
4
|
+
resource_class: resource_class,
|
5
|
+
resource: resource_record,
|
6
|
+
parent: current_parent,
|
7
|
+
}
|
8
|
+
%>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= render "interactive_resource_action_form", interactive_action: current_interactive_action %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% content_for :toolbar do %>
|
2
|
+
<%=
|
3
|
+
render partial: 'toolbar', locals: {
|
4
|
+
resource_class: resource_class,
|
5
|
+
resource: resource_record,
|
6
|
+
parent: current_parent,
|
7
|
+
}
|
8
|
+
%>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= render "interactive_resource_action_form", interactive_action: current_interactive_action %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Example View Lookup
|
2
|
+
|
3
|
+
Missing partial demo_app/blogs/_nav_user, blogs/_nav_user, resource/_nav_user with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}.
|
4
|
+
|
5
|
+
Searched in:
|
6
|
+
|
7
|
+
- "/Users/user/plutonium/demo/packages/demo_app/app/views"
|
8
|
+
- "/Users/user/plutonium/demo/app/views"
|
9
|
+
- "/Users/user/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/turbo-rails-2.0.3/app/views"
|
10
|
+
- "/Users/user/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/actiontext-7.1.3/app/views"
|
11
|
+
- "/Users/user/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/actionmailbox-7.1.3/app/views"
|
12
|
+
- "/Users/user/plutonium/plutonium/app/views"
|
13
|
+
|
14
|
+
# Partials vs Shared Partials
|
15
|
+
|
16
|
+
Rails does not apply namespace lookup to shared partials. So instead, we go with normal partials.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<% content_for :toolbar do %>
|
2
|
+
<%= render 'toolbar', resource_class: resource_class,
|
3
|
+
resource: @detail.record,
|
4
|
+
parent: current_parent do %>
|
5
|
+
<%=
|
6
|
+
render partial: 'toolbar_actions', locals: {
|
7
|
+
actions: @detail.actions.record_actions.permitted_for(policy(@detail.record)),
|
8
|
+
resource: @detail.record
|
9
|
+
}
|
10
|
+
%>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= render "resource", details: @detail %>
|
data/brakeman.ignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
{
|
2
|
+
"ignored_warnings": [
|
3
|
+
{
|
4
|
+
"warning_type": "Cross-Site Request Forgery",
|
5
|
+
"warning_code": 7,
|
6
|
+
"fingerprint": "1cb8570b8c91f38317cdf909e01e7016359846174f427e86011633c344d30fc3",
|
7
|
+
"check_name": "ForgerySetting",
|
8
|
+
"message": "`protect_from_forgery` should be called in `Plutonium::Reactor::ResourceController`",
|
9
|
+
"file": "lib/plutonium/reactor/resource_controller.rb",
|
10
|
+
"line": 10,
|
11
|
+
"link": "https://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/",
|
12
|
+
"code": null,
|
13
|
+
"render_path": null,
|
14
|
+
"location": {
|
15
|
+
"type": "controller",
|
16
|
+
"controller": "Plutonium::Reactor::ResourceController"
|
17
|
+
},
|
18
|
+
"user_input": null,
|
19
|
+
"confidence": "High",
|
20
|
+
"cwe_id": [
|
21
|
+
352
|
22
|
+
],
|
23
|
+
"note": "this is tested and confirmed to be a false flag"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"warning_type": "Mass Assignment",
|
27
|
+
"warning_code": 70,
|
28
|
+
"fingerprint": "873ee0d868e06a32e8ff387a38ddb8c6183a419813d5c20122fa9c3a887f4e54",
|
29
|
+
"check_name": "MassAssignment",
|
30
|
+
"message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
|
31
|
+
"file": "lib/plutonium/reactor/resource_controller.rb",
|
32
|
+
"line": 58,
|
33
|
+
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
34
|
+
"code": "params.require(resource_param_key).permit!",
|
35
|
+
"render_path": null,
|
36
|
+
"location": {
|
37
|
+
"type": "method",
|
38
|
+
"class": "Plutonium::Reactor::ResourceController",
|
39
|
+
"method": "resource_params"
|
40
|
+
},
|
41
|
+
"user_input": null,
|
42
|
+
"confidence": "Medium",
|
43
|
+
"cwe_id": [
|
44
|
+
915
|
45
|
+
],
|
46
|
+
"note": "we manually filter params"
|
47
|
+
}
|
48
|
+
],
|
49
|
+
"updated": "2024-02-18 00:37:39 +0000",
|
50
|
+
"brakeman_version": "6.1.2"
|
51
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# require 'active_model/validations/each_validator'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
# Based on https://gist.github.com/ssimeonov/6519423
|
6
|
+
#
|
7
|
+
# Validates the values of an Array with other validators.
|
8
|
+
# Generates error messages that include the index and value of
|
9
|
+
# invalid elements.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# validates :values, array: { presence: true, inclusion: { in: %w{ big small } } }
|
14
|
+
#
|
15
|
+
class ArrayValidator < EachValidator
|
16
|
+
attr_reader :record, :attribute, :proxy_attribute
|
17
|
+
|
18
|
+
def validate_each(record, attribute, values)
|
19
|
+
@record = record
|
20
|
+
@attribute = attribute
|
21
|
+
|
22
|
+
# Cache any existing errors temporarily.
|
23
|
+
@existing_errors = record.errors.delete(attribute) || []
|
24
|
+
|
25
|
+
# Run validations
|
26
|
+
validate_each_internal values
|
27
|
+
|
28
|
+
# Restore any existing errors.
|
29
|
+
return if @existing_errors.blank?
|
30
|
+
|
31
|
+
@existing_errors.each { |e| record.errors.add attribute, e }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def validate_each_internal(values)
|
37
|
+
[values].flatten.each_with_index do |value, index|
|
38
|
+
options.except(:if, :unless, :on, :strict).each do |key, args|
|
39
|
+
validator_options = {attributes: attribute}
|
40
|
+
validator_options.merge!(args) if args.is_a?(Hash)
|
41
|
+
|
42
|
+
next if skip? value, validator_options
|
43
|
+
|
44
|
+
validator = validator_class_for(key).new(validator_options)
|
45
|
+
validator.validate_each(record, attribute, value)
|
46
|
+
end
|
47
|
+
maybe_normalize_errors index
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def maybe_normalize_errors(index)
|
52
|
+
errors = record.errors.delete attribute
|
53
|
+
return if errors.nil?
|
54
|
+
|
55
|
+
@existing_errors += errors.map { |e| "item #{index + 1} #{e}" }
|
56
|
+
end
|
57
|
+
|
58
|
+
def skip?(value, validator_options)
|
59
|
+
return true if value.nil? && validator_options[:allow_nil]
|
60
|
+
|
61
|
+
true if value.blank? && validator_options[:allow_blank]
|
62
|
+
end
|
63
|
+
|
64
|
+
def validator_class_for(key)
|
65
|
+
validator_class_name = "#{key.to_s.camelize}Validator"
|
66
|
+
begin
|
67
|
+
validator_class_name.constantize
|
68
|
+
rescue NameError
|
69
|
+
"ActiveModel::Validations::#{validator_class_name}".constantize
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
# Validates that a file is attached
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# validates :logo, attached: true
|
10
|
+
#
|
11
|
+
class AttachedValidator < EachValidator
|
12
|
+
def validate_each(record, attribute, value)
|
13
|
+
record.errors.add(attribute, (options[:message] || "must be attached")) unless value.attached?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
# Validates that the value is a url
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# validates :website_url, url: true
|
10
|
+
#
|
11
|
+
class UrlValidator < EachValidator
|
12
|
+
URL_PATTERN = URI::DEFAULT_PARSER.make_regexp(%w[http https]).freeze
|
13
|
+
|
14
|
+
attr_reader :record, :attribute, :value
|
15
|
+
|
16
|
+
def validate_each(record, attribute, value)
|
17
|
+
@record = record
|
18
|
+
@attribute = attribute
|
19
|
+
@value = value
|
20
|
+
|
21
|
+
return if skip?
|
22
|
+
return unless validate_url
|
23
|
+
|
24
|
+
nil unless maybe_validate_image_url
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def skip?
|
30
|
+
return true if value.nil? && options[:allow_nil]
|
31
|
+
|
32
|
+
true if value.blank? && options[:allow_blank]
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_url
|
36
|
+
return true if URL_PATTERN.match?(value)
|
37
|
+
|
38
|
+
record.errors.add attribute, (options[:message] || "is not a valid URL")
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def maybe_validate_image_url
|
43
|
+
return true unless options[:image].present?
|
44
|
+
return true unless FastImage.type(value).nil?
|
45
|
+
|
46
|
+
record.errors.add(attribute, (options[:message] || "is not a valid image URL"))
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "plutonium_generators"
|
4
|
+
|
5
|
+
module Pu
|
6
|
+
module Core
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
include PlutoniumGenerators::Generator
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
desc "Set up the base requirements for Plutonium"
|
13
|
+
|
14
|
+
def start
|
15
|
+
setup_packaging_system
|
16
|
+
install_required_gems
|
17
|
+
setup_app
|
18
|
+
rescue => e
|
19
|
+
exception "#{self.class} failed:", e
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def setup_packaging_system
|
25
|
+
copy_file "config/packages.rb"
|
26
|
+
create_file "packages/.keep"
|
27
|
+
insert_into_file "config/application.rb", "\nrequire_relative \"packages\"\n", after: /Bundler\.require.*\n/
|
28
|
+
# insert_into_file "config/application.rb", indent("Plutonium.configure_rails config\n\n", 4), after: /.*< Rails::Application\n/
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_app
|
32
|
+
directory "config"
|
33
|
+
directory "app"
|
34
|
+
end
|
35
|
+
|
36
|
+
def install_required_gems
|
37
|
+
# invoke "pu:gem:simple_form"
|
38
|
+
# invoke "pu:gem:pagy"
|
39
|
+
# invoke "pu:gem:rabl"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "plutonium_generators"
|
4
|
+
|
5
|
+
module Pu
|
6
|
+
module Gem
|
7
|
+
class PagyGenerator < Rails::Generators::Base
|
8
|
+
include PlutoniumGenerators::Generator
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
desc "Install Pagy"
|
13
|
+
|
14
|
+
def start
|
15
|
+
Bundler.with_unbundled_env do
|
16
|
+
run "bundle add pagy"
|
17
|
+
end
|
18
|
+
|
19
|
+
directory "config"
|
20
|
+
rescue => e
|
21
|
+
exception "#{self.class} failed:", e
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
File without changes
|