has_helpers 5.0.2
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/.gitignore +38 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.tekton/Chart.yaml +14 -0
- data/.tekton/templates/pipelinerun.yaml +44 -0
- data/.tekton/values-main.yaml +53 -0
- data/.tekton/values-pr.yaml +40 -0
- data/.tekton/values.yaml +17 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +204 -0
- data/Gemfile +25 -0
- data/README.md +76 -0
- data/Rakefile +46 -0
- data/app/api/has_helpers/rack_api.rb +116 -0
- data/app/api/has_helpers/search_api.rb +173 -0
- data/app/assets/stylesheets/has_helpers/base.scss +5 -0
- data/app/assets/stylesheets/has_helpers/color_palette.scss +33 -0
- data/app/assets/stylesheets/has_helpers/color_palettes/default.scss +11 -0
- data/app/assets/stylesheets/has_helpers/components/dataset.scss +43 -0
- data/app/assets/stylesheets/has_helpers/mixins.scss +149 -0
- data/app/commands/has_helpers/cards/available_cards_command.rb +98 -0
- data/app/commands/has_helpers/cards/card_data_command.rb +1062 -0
- data/app/commands/reports/base_options.rb +79 -0
- data/app/commands/reports/belongs_to_options.rb +178 -0
- data/app/commands/reports/constant_options.rb +66 -0
- data/app/commands/reports/external_graphql_client.rb +116 -0
- data/app/commands/reports/fill_dates.rb +65 -0
- data/app/commands/reports/filter_option_generator.rb +186 -0
- data/app/commands/reports/generator.rb +310 -0
- data/app/commands/reports/has_many_options.rb +105 -0
- data/app/commands/reports/importer.rb +132 -0
- data/app/commands/reports/nested_attribute_options.rb +134 -0
- data/app/constants/color.rb +9 -0
- data/app/constants/file_format.rb +12 -0
- data/app/constants/has_helpers/cards/card_custom_field.rb +12 -0
- data/app/constants/has_helpers/cards/card_data_type.rb +11 -0
- data/app/constants/has_helpers/cards/card_identifier.rb +10 -0
- data/app/constants/has_helpers/cards/card_layout_type.rb +11 -0
- data/app/constants/has_helpers/cards/card_variant_type.rb +12 -0
- data/app/constants/has_helpers/link_type.rb +10 -0
- data/app/constants/has_helpers/notification_alert_status.rb +14 -0
- data/app/constants/has_helpers/notification_alert_type.rb +10 -0
- data/app/constants/has_helpers/operation.rb +11 -0
- data/app/constants/has_helpers/resource_type.rb +25 -0
- data/app/constants/icon.rb +22 -0
- data/app/constants/logical_operator.rb +7 -0
- data/app/constants/option.rb +10 -0
- data/app/constants/time_zone.rb +12 -0
- data/app/constructors/has_helpers/base_constructor.rb +62 -0
- data/app/controllers/concerns/has_helpers/service_trust/authenticated_as_service.rb +51 -0
- data/app/controllers/concerns/has_helpers/service_trust/graphql_authentication.rb +57 -0
- data/app/controllers/has_helpers/controller.rb +63 -0
- data/app/controllers/has_helpers/factory_controller.rb +261 -0
- data/app/controllers/has_helpers/graphql_extensions.rb +83 -0
- data/app/controllers/has_helpers/health_check_controller.rb +46 -0
- data/app/controllers/has_helpers/search_extensions.rb +92 -0
- data/app/controllers/has_helpers/service_trust/jwks_controller.rb +20 -0
- data/app/controllers/has_helpers/xlsx_export.rb +115 -0
- data/app/controllers/search_extensions.rb +5 -0
- data/app/graphql/has_helpers/base_type.rb +13 -0
- data/app/graphql/has_helpers/base_union.rb +9 -0
- data/app/graphql/has_helpers/enums/resource_enum.rb +24 -0
- data/app/graphql/has_helpers/middleware/application_access.rb +26 -0
- data/app/graphql/has_helpers/mutations/base.rb +27 -0
- data/app/graphql/has_helpers/mutations/external_data_sync.rb +72 -0
- data/app/graphql/has_helpers/mutations/mark_individual_alert_read.rb +31 -0
- data/app/graphql/has_helpers/mutations/mark_notifications_read.rb +50 -0
- data/app/graphql/has_helpers/mutations/toggle_favorite.rb +39 -0
- data/app/graphql/has_helpers/resolvers/app_nav.rb +107 -0
- data/app/graphql/has_helpers/resolvers/base.rb +27 -0
- data/app/graphql/has_helpers/resolvers/cards/available_cards.rb +31 -0
- data/app/graphql/has_helpers/resolvers/cards/card_data.rb +74 -0
- data/app/graphql/has_helpers/resolvers/cards/hover_card_data.rb +153 -0
- data/app/graphql/has_helpers/resolvers/favorite.rb +62 -0
- data/app/graphql/has_helpers/resolvers/internal/roles.rb +54 -0
- data/app/graphql/has_helpers/resolvers/is_favorite.rb +24 -0
- data/app/graphql/has_helpers/resolvers/list_notification_alerts.rb +47 -0
- data/app/graphql/has_helpers/resolvers/lookup.rb +36 -0
- data/app/graphql/has_helpers/resolvers/recently_viewed.rb +54 -0
- data/app/graphql/has_helpers/resolvers/resource_tab.rb +22 -0
- data/app/graphql/has_helpers/resolvers/search.rb +18 -0
- data/app/graphql/has_helpers/resolvers/search_query.rb +38 -0
- data/app/graphql/has_helpers/resolvers/user_application_order.rb +35 -0
- data/app/graphql/has_helpers/resources/organization_option_resource.rb +28 -0
- data/app/graphql/has_helpers/resources/organization_resource_resource.rb +18 -0
- data/app/graphql/has_helpers/resources/resource_group_resource.rb +10 -0
- data/app/graphql/has_helpers/resources/resource_resource.rb +21 -0
- data/app/graphql/has_helpers/resources/user_role_resource.rb +9 -0
- data/app/graphql/has_helpers/types/application_order_type.rb +18 -0
- data/app/graphql/has_helpers/types/cards/available_card_type.rb +20 -0
- data/app/graphql/has_helpers/types/cards/card_badge_type.rb +12 -0
- data/app/graphql/has_helpers/types/cards/card_config_type.rb +18 -0
- data/app/graphql/has_helpers/types/cards/card_data_type.rb +13 -0
- data/app/graphql/has_helpers/types/cards/card_entry_field_type.rb +21 -0
- data/app/graphql/has_helpers/types/cards/card_entry_type.rb +12 -0
- data/app/graphql/has_helpers/types/cards/card_field_config_type.rb +17 -0
- data/app/graphql/has_helpers/types/layouts/app_nav/link_section_type.rb +17 -0
- data/app/graphql/has_helpers/types/layouts/app_nav/link_type.rb +20 -0
- data/app/graphql/has_helpers/types/layouts/app_nav/sub_link_type.rb +17 -0
- data/app/graphql/has_helpers/types/layouts/app_nav/type.rb +16 -0
- data/app/graphql/has_helpers/types/lookup.rb +16 -0
- data/app/graphql/has_helpers/types/resource_tab/type.rb +15 -0
- data/app/graphql/has_helpers/types/role_type.rb +13 -0
- data/app/graphql/has_helpers/types/search/detail_badge_type.rb +15 -0
- data/app/graphql/has_helpers/types/search/detail_item_type.rb +14 -0
- data/app/graphql/has_helpers/types/search/detail_type.rb +16 -0
- data/app/graphql/has_helpers/types/search/filter_operation_enum.rb +19 -0
- data/app/graphql/has_helpers/types/search/input_type.rb +16 -0
- data/app/graphql/has_helpers/types/search/result_type.rb +72 -0
- data/app/graphql/has_helpers/types/search/search_filter_input_type.rb +17 -0
- data/app/graphql/has_helpers/types/search/type.rb +17 -0
- data/app/importers/has_helpers/cards/importer.rb +1223 -0
- data/app/lib/has_helpers/application_helper.rb +21 -0
- data/app/lib/has_helpers/dn/processor.rb +55 -0
- data/app/lib/has_helpers/dn/refresh.rb +13 -0
- data/app/lib/has_helpers/dn/utils/backfill_utils.rb +80 -0
- data/app/lib/has_helpers/dn/utils/query_utils.rb +216 -0
- data/app/lib/has_helpers/feature.rb +88 -0
- data/app/lib/has_helpers/hq_exception.rb +18 -0
- data/app/lib/has_helpers/index.rb +890 -0
- data/app/lib/has_helpers/organization_merge.rb +128 -0
- data/app/lib/has_helpers/query/elasticsearch.rb +20 -0
- data/app/lib/has_helpers/query/provider.rb +105 -0
- data/app/lib/has_helpers/query/sql.rb +133 -0
- data/app/lib/has_helpers/query.rb +14 -0
- data/app/lib/has_helpers/search/elasticsearch.rb +41 -0
- data/app/lib/has_helpers/search/elasticsearch_shared.rb +70 -0
- data/app/lib/has_helpers/search/provider.rb +149 -0
- data/app/lib/has_helpers/search/search_utils.rb +74 -0
- data/app/lib/has_helpers/search/sql_search.rb +219 -0
- data/app/lib/has_helpers/search.rb +46 -0
- data/app/models/ability.rb +233 -0
- data/app/models/has_helpers/application.rb +47 -0
- data/app/models/has_helpers/application_record.rb +7 -0
- data/app/models/has_helpers/cards/card_builder/base.rb +74 -0
- data/app/models/has_helpers/cards/card_builder/card_definition_builder.rb +486 -0
- data/app/models/has_helpers/cards/card_builder/definition_context.rb +82 -0
- data/app/models/has_helpers/cards/card_builder/field_builder.rb +142 -0
- data/app/models/has_helpers/cards/card_builder/resource_builder.rb +34 -0
- data/app/models/has_helpers/cards/card_definition.rb +41 -0
- data/app/models/has_helpers/cards/card_definition_resource.rb +19 -0
- data/app/models/has_helpers/cards/card_field.rb +39 -0
- data/app/models/has_helpers/cards/registry.rb +115 -0
- data/app/models/has_helpers/cards/role_card_field.rb +28 -0
- data/app/models/has_helpers/cards/role_resource_card.rb +41 -0
- data/app/models/has_helpers/dn_utils.rb +61 -0
- data/app/models/has_helpers/favorite.rb +20 -0
- data/app/models/has_helpers/master_record.rb +18 -0
- data/app/models/has_helpers/notification_alert.rb +52 -0
- data/app/models/has_helpers/organization.rb +16 -0
- data/app/models/has_helpers/organization_link.rb +92 -0
- data/app/models/has_helpers/organization_methods.rb +62 -0
- data/app/models/has_helpers/organization_option.rb +31 -0
- data/app/models/has_helpers/organization_resource.rb +45 -0
- data/app/models/has_helpers/pending_db_operation.rb +31 -0
- data/app/models/has_helpers/recently_viewed.rb +34 -0
- data/app/models/has_helpers/reindex_queue.rb +43 -0
- data/app/models/has_helpers/resource.rb +38 -0
- data/app/models/has_helpers/resource_group.rb +15 -0
- data/app/models/has_helpers/restriction.rb +15 -0
- data/app/models/has_helpers/restriction_operation.rb +13 -0
- data/app/models/has_helpers/role.rb +20 -0
- data/app/models/has_helpers/service_trust/audit_log.rb +20 -0
- data/app/models/has_helpers/service_trust/key.rb +56 -0
- data/app/models/has_helpers/stat.rb +13 -0
- data/app/models/has_helpers/user.rb +18 -0
- data/app/models/has_helpers/user_methods.rb +184 -0
- data/app/models/has_helpers/user_organization.rb +33 -0
- data/app/models/has_helpers/user_role.rb +27 -0
- data/app/models/has_helpers/user_session.rb +19 -0
- data/app/presenters/has_helpers/barcode_base_presenter.rb +113 -0
- data/app/presenters/has_helpers/base_presenter.rb +100 -0
- data/app/presenters/has_helpers/cacheable_item.rb +28 -0
- data/app/presenters/has_helpers/item_presenter.rb +52 -0
- data/app/presenters/has_helpers/items_presenter.rb +33 -0
- data/app/presenters/has_helpers/resource/action_presenter.rb +8 -0
- data/app/presenters/has_helpers/resource/cell_presenter.rb +52 -0
- data/app/presenters/has_helpers/resource/email_presenter.rb +34 -0
- data/app/presenters/has_helpers/resource/form_presenter.rb +76 -0
- data/app/presenters/has_helpers/resource/info_collection_presenter.rb +33 -0
- data/app/presenters/has_helpers/resource/info_presenter.rb +34 -0
- data/app/presenters/has_helpers/resource/list_presenter.rb +120 -0
- data/app/presenters/has_helpers/resource/note_presenter.rb +14 -0
- data/app/presenters/has_helpers/resource/row_presenter.rb +25 -0
- data/app/presenters/has_helpers/resource/tag_presenter.rb +31 -0
- data/app/presenters/has_helpers/search_presenter.rb +230 -0
- data/app/triggers/has_helpers/erase_denormalized_belongs_to_column_trigger.rb +85 -0
- data/app/triggers/has_helpers/limit_favorites.rb +97 -0
- data/app/utils/has_helpers/redis_configurable.rb +79 -0
- data/app/utils/has_helpers/sync_utils.rb +234 -0
- data/app/views/has_helpers/actions/_action.html.erb +31 -0
- data/app/views/has_helpers/alerts/_alert.html.erb +3 -0
- data/app/views/has_helpers/barcodes.html.erb +36 -0
- data/app/views/has_helpers/containers/_container.html.erb +3 -0
- data/app/views/has_helpers/email_notifier/system.html.erb +8 -0
- data/app/views/has_helpers/email_notifier/system.text.erb +7 -0
- data/app/views/has_helpers/enumerables/_enumerable.html.erb +1 -0
- data/app/views/has_helpers/icons/_icon.html.erb +1 -0
- data/app/views/has_helpers/render_objects/_render_object.html.erb +1 -0
- data/app/views/has_helpers/services/_service.html.erb +1 -0
- data/app/views/has_helpers/text_nodes/_text_node.html.erb +4 -0
- data/app/views/has_helpers/ui_attributes/_html_attrs.html.erb +1 -0
- data/app/workers/elasticsearch_process_queue.rb +11 -0
- data/app/workers/elasticsearch_reindex.rb +11 -0
- data/app/workers/elasticsearch_reindex_scheduler.rb +35 -0
- data/app/workers/good_job/configurable_backfill.rb +64 -0
- data/app/workers/good_job/cron_denormalization_stats_manager.rb +39 -0
- data/app/workers/good_job/denormalization_stats_worker.rb +57 -0
- data/app/workers/good_job/dn_update_worker.rb +30 -0
- data/app/workers/good_job/dn_worker.rb +47 -0
- data/app/workers/good_job/elasticsearch_old_index_cleaner_worker.rb +113 -0
- data/app/workers/good_job/elasticsearch_on_finish_reindex.rb +26 -0
- data/app/workers/good_job/elasticsearch_process_batch.rb +78 -0
- data/app/workers/good_job/elasticsearch_process_change_logs_master_worker.rb +27 -0
- data/app/workers/good_job/elasticsearch_process_change_logs_worker.rb +155 -0
- data/app/workers/good_job/elasticsearch_process_queue.rb +50 -0
- data/app/workers/good_job/elasticsearch_reindex.rb +31 -0
- data/app/workers/has_helpers/cards/orphan_card_sweeper.rb +28 -0
- data/app/workers/has_helpers/db_operations/clean_stats_worker.rb +42 -0
- data/app/workers/has_helpers/db_operations/helper_worker.rb +131 -0
- data/app/workers/has_helpers/db_operations/main_worker.rb +164 -0
- data/app/workers/has_helpers/db_operations/operations.rb +134 -0
- data/app/workers/has_helpers/db_operations/update_operations_stats_resume_worker.rb +35 -0
- data/app/workers/has_helpers/default_worker.rb +17 -0
- data/app/workers/has_helpers/good_job/notification_alert_cleanup_worker.rb +43 -0
- data/app/workers/has_helpers/service_trust/audit_log_cleanup_worker.rb +19 -0
- data/app/workers/sidekiq/elasticsearch_old_index_cleaner_worker.rb +112 -0
- data/app/workers/sidekiq/elasticsearch_process_batch.rb +87 -0
- data/app/workers/sidekiq/elasticsearch_process_queue.rb +40 -0
- data/app/workers/sidekiq/elasticsearch_reindex.rb +53 -0
- data/config/initializers/action_view.rb +7 -0
- data/config/initializers/inflections.rb +24 -0
- data/config/initializers/marginalia.rb +8 -0
- data/config/initializers/mime_types.rb +6 -0
- data/config/initializers/opentelemetry.rb +12 -0
- data/config/initializers/redis_conf.rb +40 -0
- data/config/initializers/searchkick.rb +9 -0
- data/config/initializers/will_paginate.rb +39 -0
- data/config/redis.yml +12 -0
- data/config/routes.rb +27 -0
- data/config/service_trust_routes.rb +5 -0
- data/config.ru +9 -0
- data/db/migrate/20230127194725_create_organization_table.rb +25 -0
- data/db/migrate/20230127194726_validate_organization_foreign_keys.rb +7 -0
- data/db/migrate/20230206141413_create_security_models.rb +42 -0
- data/db/migrate/20230206141513_create_restriction_model.rb +20 -0
- data/db/migrate/20230206142613_add_security_indexes.rb +14 -0
- data/db/migrate/20230206143513_security_model_constants_seed.rb +8 -0
- data/db/migrate/20230206161513_add_organization_to_security_models.rb +13 -0
- data/db/migrate/20230209121019_create_search_group_models.rb +36 -0
- data/db/migrate/20230209122919_add_search_group_indexes.rb +21 -0
- data/db/migrate/20230209181832_add_search_group_resources_type_constraint_trigger.rb +61 -0
- data/db/migrate/20230313220337_create_table_user_sessions.rb +31 -0
- data/db/migrate/20230517141106_update_resource_types.rb +12 -0
- data/db/migrate/20230518194611_add_resources_contraints.rb +17 -0
- data/db/migrate/20230518194642_create_nested_resource_model.rb +21 -0
- data/db/migrate/20230518194645_validate_security_models_constraints.rb +23 -0
- data/db/migrate/20230608125037_add_inactive_field_to_user_sessions.rb +7 -0
- data/db/migrate/20230919191525_add_parent_id_to_resources.rb +8 -0
- data/db/migrate/20230919191535_validate_parent_id_fk_resources.rb +7 -0
- data/db/migrate/20230919210456_drop_nested_resources.rb +7 -0
- data/db/migrate/20231222135620_add_user_role.rb +19 -0
- data/db/migrate/20240108172021_create_favorites_table.rb +20 -0
- data/db/migrate/20240108190209_create_organization_link_table_if_doesnt_exists.rb +31 -0
- data/db/migrate/20240109211445_validate_fks_org_links.rb +9 -0
- data/db/migrate/20240110135440_create_recently_vieweds.rb +20 -0
- data/db/migrate/20240112185312_link_type_options_seed.rb +7 -0
- data/db/migrate/20240116173201_organization_link_resource_tab_constraints.rb +19 -0
- data/db/migrate/20240131160949_add_user_organizations_table.rb +32 -0
- data/db/migrate/20240212132519_add_organization_in_user_sessions.rb +13 -0
- data/db/migrate/20240227135052_add_user_organization_composite_fks.rb +32 -0
- data/db/migrate/20240312193501_update_organization_links.rb +11 -0
- data/db/migrate/20240426185902_add_user_organizations_current_organization_column.rb +12 -0
- data/db/migrate/20240429214601_add_primary_trigger.rb +10 -0
- data/db/migrate/20241112131819_add_json_file_format_seed.rb +7 -0
- data/db/migrate/20250520133417_create_restriction_operations.rb +18 -0
- data/db/migrate/20250520133420_validate_create_restriction_operations.rb +8 -0
- data/db/migrate/20250520140642_add_indexes_to_restrictions.rb +9 -0
- data/db/migrate/20250529130741_create_notification_alerts_table.rb +28 -0
- data/db/migrate/20250530223332_create_data_migrations_table.rb +19 -0
- data/db/migrate/20250605121622_seed_notification_alert_status.rb +7 -0
- data/db/migrate/20250605131439_seed_notification_alert_types.rb +7 -0
- data/db/migrate/20250606173128_update_notification_alert_length_constraint.rb +18 -0
- data/db/migrate/20250606174043_validate_notification_alert_length_constraints.rb +8 -0
- data/db/migrate/20250624183000_add_data_import_alert_type.rb +11 -0
- data/db/migrate/20250722183935_create_organization_options_table.rb +38 -0
- data/db/migrate/20250722192724_validate_organization_options_fks_and_constraints.rb +32 -0
- data/db/migrate/20250722192936_add_indexes_to_organization_options_table.rb +15 -0
- data/db/migrate/20250915132448_add_column_restrictions_hash.rb +7 -0
- data/db/migrate/20250917143211_add_column_permissions_hash.rb +7 -0
- data/db/migrate/20251001145950_add_trust_this_device.rb +7 -0
- data/db/migrate/20251021130835_add_backend_urls_to_applications_table.rb +13 -0
- data/db/migrate/20251021172715_validate_backend_urls_constraints_in_applications.rb +9 -0
- data/db/migrate/20251030200020_create_card_definitions.rb +23 -0
- data/db/migrate/20251030201012_create_card_definition_resources.rb +24 -0
- data/db/migrate/20251030201236_create_card_fields.rb +34 -0
- data/db/migrate/20251103194317_create_role_resource_cards.rb +37 -0
- data/db/migrate/20251103194426_create_role_card_fields.rb +34 -0
- data/db/migrate/20251107173218_validate_columns_from_cards.rb +17 -0
- data/db/migrate/20251111173212_add_column_application_array.rb +7 -0
- data/db/migrate/20251112203326_add_card_types.rb +10 -0
- data/db/migrate/20251115120000_add_virtual_cards_support.rb +28 -0
- data/db/migrate/20251202231256_add_org_scoped_fk_role_resource_cards_to_roles.rb +14 -0
- data/db/migrate/20260105134504_add_accessor_field_resource_type.rb +7 -0
- data/db/migrate/20260115123000_add_default_visibility_to_card_definitions.rb +9 -0
- data/db/migrate/20260120175037_is_new_admin.rb +9 -0
- data/db/migrate/20260122392008_add_stats_table.rb +17 -0
- data/db/migrate/20260414204718_add_index_to_stats_table.rb +10 -0
- data/db/migrate/20260509120000_create_service_trust_keys.rb +25 -0
- data/db/migrate/20260509120001_create_service_trust_audit_logs.rb +26 -0
- data/db/migrate/20260511120000_add_direction_to_service_trust_audit_logs.rb +17 -0
- data/db/migrate/20260511121000_remove_role_fk_from_role_resource_cards.rb +19 -0
- data/db/migrate/20260511121001_add_disabled_at_to_role_resource_cards.rb +10 -0
- data/db/migrate/20260605120100_seed_hover_card_options.rb +8 -0
- data/db/migrate/20260608120000_seed_badge_list_card_data_type.rb +7 -0
- data/db/migrate/20260727000000_add_two_factor_trust_id_to_user_sessions.rb +11 -0
- data/db/seeds.rb +14 -0
- data/docs/Elasticsearch.md +23 -0
- data/docs/Search_API.md +126 -0
- data/docs/cards_role_proxy.md +107 -0
- data/docs/factory_api.md +135 -0
- data/has-helpers-pr-289-pipeline.yaml +16 -0
- data/has-helpers-pr-298-pipeline.yaml +15 -0
- data/has_helpers.gemspec +68 -0
- data/lib/active_record/migration/active_migration_patch.rb +123 -0
- data/lib/generators/has_helpers/install/USAGE +8 -0
- data/lib/generators/has_helpers/install/install_generator.rb +22 -0
- data/lib/generators/has_helpers/install/templates/migrate/has_helpers_initial_setup.rb +26 -0
- data/lib/has_helpers/active_record/base.rb +50 -0
- data/lib/has_helpers/active_record/date_range.rb +228 -0
- data/lib/has_helpers/active_record/nested_resource.rb +58 -0
- data/lib/has_helpers/active_record/validation.rb +63 -0
- data/lib/has_helpers/active_record.rb +520 -0
- data/lib/has_helpers/app/command.rb +107 -0
- data/lib/has_helpers/app.rb +10 -0
- data/lib/has_helpers/assets_precompile_helper.rb +20 -0
- data/lib/has_helpers/attributes.rb +196 -0
- data/lib/has_helpers/aws.rb +67 -0
- data/lib/has_helpers/cards/cache.rb +49 -0
- data/lib/has_helpers/cards/config.rb +42 -0
- data/lib/has_helpers/cards/remote_role.rb +27 -0
- data/lib/has_helpers/cards/remote_roles.rb +75 -0
- data/lib/has_helpers/cards/roles.rb +55 -0
- data/lib/has_helpers/cards.rb +34 -0
- data/lib/has_helpers/concerns/hydrate_concern.rb +76 -0
- data/lib/has_helpers/concerns/importable_accessors.rb +25 -0
- data/lib/has_helpers/concerns/restrictions_parseable.rb +51 -0
- data/lib/has_helpers/config.rb +11 -0
- data/lib/has_helpers/constant.rb +578 -0
- data/lib/has_helpers/constraints.rb +10 -0
- data/lib/has_helpers/core_ext/array.rb +28 -0
- data/lib/has_helpers/core_ext/date/infinity.rb +25 -0
- data/lib/has_helpers/core_ext/date.rb +39 -0
- data/lib/has_helpers/core_ext/enumerable.rb +20 -0
- data/lib/has_helpers/core_ext/false_class.rb +14 -0
- data/lib/has_helpers/core_ext/float.rb +18 -0
- data/lib/has_helpers/core_ext/hash.rb +71 -0
- data/lib/has_helpers/core_ext/integer.rb +18 -0
- data/lib/has_helpers/core_ext/nil_class.rb +30 -0
- data/lib/has_helpers/core_ext/object.rb +60 -0
- data/lib/has_helpers/core_ext/proc.rb +16 -0
- data/lib/has_helpers/core_ext/string.rb +81 -0
- data/lib/has_helpers/core_ext/symbol.rb +17 -0
- data/lib/has_helpers/core_ext/true_class.rb +14 -0
- data/lib/has_helpers/cursor.rb +46 -0
- data/lib/has_helpers/data_migration/base.rb +293 -0
- data/lib/has_helpers/data_migration/large_worker.rb +20 -0
- data/lib/has_helpers/data_migration/master_worker.rb +33 -0
- data/lib/has_helpers/data_migration/migrator.rb +83 -0
- data/lib/has_helpers/data_migration/model.rb +18 -0
- data/lib/has_helpers/data_migration/small_worker.rb +20 -0
- data/lib/has_helpers/data_migration.rb +8 -0
- data/lib/has_helpers/engine.rb +47 -0
- data/lib/has_helpers/extensions.rb +17 -0
- data/lib/has_helpers/factory_api.rb +47 -0
- data/lib/has_helpers/factory_scenario/definition.rb +33 -0
- data/lib/has_helpers/factory_scenario/dsl.rb +80 -0
- data/lib/has_helpers/factory_scenario/factory_bot_override.rb +53 -0
- data/lib/has_helpers/factory_scenario/registry.rb +31 -0
- data/lib/has_helpers/factory_scenario/runner.rb +285 -0
- data/lib/has_helpers/factory_scenario.rb +27 -0
- data/lib/has_helpers/fixed_expiration_time_cache_session_store.rb +20 -0
- data/lib/has_helpers/flattener/association.rb +140 -0
- data/lib/has_helpers/flattener/attribute.rb +42 -0
- data/lib/has_helpers/flattener/base.rb +428 -0
- data/lib/has_helpers/flattener/column/types.rb +71 -0
- data/lib/has_helpers/flattener/column.rb +97 -0
- data/lib/has_helpers/flattener/pivot.rb +49 -0
- data/lib/has_helpers/flattener/reset.rb +33 -0
- data/lib/has_helpers/flattener/resource.rb +114 -0
- data/lib/has_helpers/flattener/resource_generator.rb +21 -0
- data/lib/has_helpers/flattener/utils.rb +14 -0
- data/lib/has_helpers/flattener.rb +53 -0
- data/lib/has_helpers/hash_accessors.rb +62 -0
- data/lib/has_helpers/helpers/application.rb +291 -0
- data/lib/has_helpers/index/config.rb +15 -0
- data/lib/has_helpers/lazy_config.rb +61 -0
- data/lib/has_helpers/resource_importer.rb +260 -0
- data/lib/has_helpers/resources.rb +127 -0
- data/lib/has_helpers/rspec/constants.rb +61 -0
- data/lib/has_helpers/rspec/factories.rb +11 -0
- data/lib/has_helpers/rspec.rb +22 -0
- data/lib/has_helpers/sentry/graphql_trace.rb +37 -0
- data/lib/has_helpers/serializer.rb +41 -0
- data/lib/has_helpers/service_trust/audit.rb +45 -0
- data/lib/has_helpers/service_trust/authorization.rb +34 -0
- data/lib/has_helpers/service_trust/bearer_token.rb +23 -0
- data/lib/has_helpers/service_trust/capability.rb +32 -0
- data/lib/has_helpers/service_trust/client/response.rb +13 -0
- data/lib/has_helpers/service_trust/client/retry.rb +35 -0
- data/lib/has_helpers/service_trust/client.rb +128 -0
- data/lib/has_helpers/service_trust/configuration.rb +76 -0
- data/lib/has_helpers/service_trust/engine.rb +10 -0
- data/lib/has_helpers/service_trust/errors.rb +32 -0
- data/lib/has_helpers/service_trust/graphql/authorizable.rb +72 -0
- data/lib/has_helpers/service_trust/graphql_client.rb +54 -0
- data/lib/has_helpers/service_trust/jwks_client.rb +133 -0
- data/lib/has_helpers/service_trust/jwt_codec.rb +45 -0
- data/lib/has_helpers/service_trust/key_manager.rb +160 -0
- data/lib/has_helpers/service_trust/rate_limiter.rb +27 -0
- data/lib/has_helpers/service_trust/replay_cache.rb +26 -0
- data/lib/has_helpers/service_trust/signer.rb +47 -0
- data/lib/has_helpers/service_trust/test.rb +60 -0
- data/lib/has_helpers/service_trust/verifier.rb +85 -0
- data/lib/has_helpers/service_trust/verify_middleware.rb +55 -0
- data/lib/has_helpers/service_trust.rb +51 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_addresses.rb +42 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_advisors.rb +272 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_emails.rb +37 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_organizations.rb +48 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_people.rb +34 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_phones.rb +41 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_states.rb +26 -0
- data/lib/has_helpers/test_helpers/factory_data/unit_webs.rb +31 -0
- data/lib/has_helpers/test_helpers/shoulda_helpers.rb +249 -0
- data/lib/has_helpers/ui_attributes.rb +39 -0
- data/lib/has_helpers/utils/action.rb +87 -0
- data/lib/has_helpers/utils/active_record_utils.rb +40 -0
- data/lib/has_helpers/utils/alert.rb +42 -0
- data/lib/has_helpers/utils/container.rb +46 -0
- data/lib/has_helpers/utils/dataset.rb +34 -0
- data/lib/has_helpers/utils/email_notifier.rb +15 -0
- data/lib/has_helpers/utils/icon.rb +66 -0
- data/lib/has_helpers/utils/input.rb +45 -0
- data/lib/has_helpers/utils/log_notifier.rb +79 -0
- data/lib/has_helpers/utils/render_object.rb +32 -0
- data/lib/has_helpers/utils/s3_utils.rb +37 -0
- data/lib/has_helpers/utils/service.rb +87 -0
- data/lib/has_helpers/utils/slack_conf.rb +31 -0
- data/lib/has_helpers/utils/slack_notifier.rb +42 -0
- data/lib/has_helpers/utils/text_node.rb +34 -0
- data/lib/has_helpers/utils/user_restrictions.rb +266 -0
- data/lib/has_helpers/utils.rb +19 -0
- data/lib/has_helpers/version.rb +6 -0
- data/lib/has_helpers/web_socket_publisher.rb +20 -0
- data/lib/has_helpers/webhook.rb +17 -0
- data/lib/has_helpers.rb +63 -0
- data/lib/hq/resource.rb +55 -0
- data/lib/hq/structure/inserts.rb +176 -0
- data/lib/hq/structure.rb +115 -0
- data/lib/tasks/has_helpers/service_trust.rake +39 -0
- data/script/rails +10 -0
- data/sorbet/config +5 -0
- data/sorbet/rbi/gems/actionpack.rbi +1361 -0
- data/sorbet/rbi/gems/activemodel.rbi +755 -0
- data/sorbet/rbi/gems/activerecord.rbi +4713 -0
- data/sorbet/rbi/gems/activesupport.rbi +1970 -0
- data/sorbet/rbi/gems/barby.rbi +129 -0
- data/sorbet/rbi/gems/better_errors.rbi +155 -0
- data/sorbet/rbi/gems/binding_of_caller.rbi +22 -0
- data/sorbet/rbi/gems/byebug.rbi +19 -0
- data/sorbet/rbi/gems/chronic.rbi +480 -0
- data/sorbet/rbi/gems/chunky_png.rbi +510 -0
- data/sorbet/rbi/gems/climate_control.rbi +45 -0
- data/sorbet/rbi/gems/coderay.rbi +91 -0
- data/sorbet/rbi/gems/concurrent-ruby.rbi +1587 -0
- data/sorbet/rbi/gems/debug_inspector.rbi +18 -0
- data/sorbet/rbi/gems/erubi.rbi +26 -0
- data/sorbet/rbi/gems/holidays.rbi +362 -0
- data/sorbet/rbi/gems/i18n.rbi +132 -0
- data/sorbet/rbi/gems/method_source.rbi +63 -0
- data/sorbet/rbi/gems/mime-types-data.rbi +16 -0
- data/sorbet/rbi/gems/mime-types.rbi +217 -0
- data/sorbet/rbi/gems/mimemagic.rbi +36 -0
- data/sorbet/rbi/gems/minitest.rbi +282 -0
- data/sorbet/rbi/gems/mustache.rbi +151 -0
- data/sorbet/rbi/gems/paperclip.rbi +644 -0
- data/sorbet/rbi/gems/parallel.rbi +81 -0
- data/sorbet/rbi/gems/parallel_tests.rbi +27 -0
- data/sorbet/rbi/gems/pry-rails.rbi +71 -0
- data/sorbet/rbi/gems/pry.rbi +1964 -0
- data/sorbet/rbi/gems/rack.rbi +228 -0
- data/sorbet/rbi/gems/railties.rbi +364 -0
- data/sorbet/rbi/gems/rspec-core.rbi +1704 -0
- data/sorbet/rbi/gems/rspec-expectations.rbi +389 -0
- data/sorbet/rbi/gems/rspec-support.rbi +206 -0
- data/sorbet/rbi/gems/rspec.rbi +14 -0
- data/sorbet/rbi/gems/spreadsheet_architect.rbi +10 -0
- data/sorbet/rbi/gems/sprockets.rbi +659 -0
- data/sorbet/rbi/gems/terrapin.rbi +115 -0
- data/sorbet/rbi/gems/testhq.rbi +14 -0
- data/sorbet/rbi/gems/thor.rbi +482 -0
- data/sorbet/rbi/gems/thread_safe.rbi +81 -0
- data/sorbet/rbi/gems/tzinfo.rbi +407 -0
- data/sorbet/rbi/gems/zeitwerk.rbi +131 -0
- data/sorbet/rbi/hidden-definitions/errors.txt +35111 -0
- data/sorbet/rbi/hidden-definitions/hidden.rbi +59974 -0
- data/sorbet/rbi/sorbet-typed/lib/actionmailer/all/actionmailer.rbi +13 -0
- data/sorbet/rbi/sorbet-typed/lib/actionpack/all/actionpack.rbi +855 -0
- data/sorbet/rbi/sorbet-typed/lib/actionview/all/actionview.rbi +314 -0
- data/sorbet/rbi/sorbet-typed/lib/activemodel/all/activemodel.rbi +423 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/>=5.2/activerecord.rbi +17 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1415 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/~>6.0.0/activerecord.rbi +475 -0
- data/sorbet/rbi/sorbet-typed/lib/activestorage/>=6.0.0/activestorage.rbi +19 -0
- data/sorbet/rbi/sorbet-typed/lib/activestorage/all/activestorage.rbi +173 -0
- data/sorbet/rbi/sorbet-typed/lib/activesupport/>=6.0.0.rc1/activesupport.rbi +23 -0
- data/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +625 -0
- data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
- data/sorbet/rbi/sorbet-typed/lib/minitest/all/minitest.rbi +99 -0
- data/sorbet/rbi/sorbet-typed/lib/railties/all/railties.rbi +25 -0
- data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +254 -0
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
- data/sorbet/rbi/todo.rbi +244 -0
- data/spec/commands/cards/available_cards_command_spec.rb +90 -0
- data/spec/commands/cards/card_data_command_spec.rb +1048 -0
- data/spec/constructors/has_helpers/base_constructor_spec.rb +49 -0
- data/spec/controllers/has_helpers/controller_spec.rb +71 -0
- data/spec/controllers/has_helpers/xlsx_export_spec.rb +96 -0
- data/spec/factories/advisors.rb +20 -0
- data/spec/factories/anonymous_cowards.rb +5 -0
- data/spec/factories/applications.rb +5 -0
- data/spec/factories/appointments.rb +6 -0
- data/spec/factories/attachment.rb +15 -0
- data/spec/factories/audits.rb +5 -0
- data/spec/factories/basic_schedules.rb +12 -0
- data/spec/factories/cards/card_definition_resources.rb +7 -0
- data/spec/factories/cards/card_definitions.rb +11 -0
- data/spec/factories/cards/card_fields.rb +22 -0
- data/spec/factories/cards/role_card_fields.rb +17 -0
- data/spec/factories/cards/role_resource_cards.rb +12 -0
- data/spec/factories/constant_definition.rb +7 -0
- data/spec/factories/contracts.rb +10 -0
- data/spec/factories/data_migration_models.rb +9 -0
- data/spec/factories/demographics.rb +22 -0
- data/spec/factories/events.rb +21 -0
- data/spec/factories/firms.rb +21 -0
- data/spec/factories/imports.rb +9 -0
- data/spec/factories/meetups.rb +13 -0
- data/spec/factories/organizations.rb +13 -0
- data/spec/factories/policies.rb +7 -0
- data/spec/factories/policy_notes.rb +9 -0
- data/spec/factories/read_only_values.rb +7 -0
- data/spec/factories/resources.rb +7 -0
- data/spec/factories/roles.rb +11 -0
- data/spec/factories/schedules.rb +13 -0
- data/spec/factories/shared/flattener/attributes.rb +10 -0
- data/spec/factories/shared/flattener/columns.rb +6 -0
- data/spec/factories/shared/flattener/resources.rb +5 -0
- data/spec/factories/templates.rb +12 -0
- data/spec/factories/user_organizations.rb +23 -0
- data/spec/factories/user_session.rb +11 -0
- data/spec/factories/users.rb +55 -0
- data/spec/fixtures/sample_config.yml +3 -0
- data/spec/graphql/has_helpers/mutations/external_data_sync_spec.rb +101 -0
- data/spec/graphql/has_helpers/resolvers/cards/available_cards_spec.rb +36 -0
- data/spec/graphql/has_helpers/resolvers/cards/card_data_spec.rb +42 -0
- data/spec/graphql/has_helpers/resolvers/cards/hover_card_data_spec.rb +59 -0
- data/spec/has_helpers/cards/cache_spec.rb +58 -0
- data/spec/has_helpers/cards/config_spec.rb +68 -0
- data/spec/has_helpers/cards/orphan_card_sweeper_spec.rb +97 -0
- data/spec/has_helpers/cards/remote_role_spec.rb +17 -0
- data/spec/has_helpers/cards/remote_roles_spec.rb +97 -0
- data/spec/has_helpers/cards/roles_spec.rb +52 -0
- data/spec/has_helpers/cards/smoke_spec.rb +168 -0
- data/spec/has_helpers/cards/support.rb +52 -0
- data/spec/has_helpers/resolvers/internal/roles_spec.rb +73 -0
- data/spec/has_helpers/service_trust/audit_log_cleanup_worker_spec.rb +33 -0
- data/spec/has_helpers/service_trust/audit_spec.rb +70 -0
- data/spec/has_helpers/service_trust/authenticated_as_service_spec.rb +65 -0
- data/spec/has_helpers/service_trust/authorization_spec.rb +37 -0
- data/spec/has_helpers/service_trust/capability_spec.rb +35 -0
- data/spec/has_helpers/service_trust/client_spec.rb +129 -0
- data/spec/has_helpers/service_trust/configuration_spec.rb +35 -0
- data/spec/has_helpers/service_trust/engine_spec.rb +13 -0
- data/spec/has_helpers/service_trust/errors_spec.rb +23 -0
- data/spec/has_helpers/service_trust/graphql_authentication_spec.rb +59 -0
- data/spec/has_helpers/service_trust/graphql_authorizable_spec.rb +91 -0
- data/spec/has_helpers/service_trust/graphql_client_spec.rb +47 -0
- data/spec/has_helpers/service_trust/jwks_client_spec.rb +85 -0
- data/spec/has_helpers/service_trust/jwks_controller_spec.rb +47 -0
- data/spec/has_helpers/service_trust/jwt_codec_spec.rb +30 -0
- data/spec/has_helpers/service_trust/key_manager_spec.rb +80 -0
- data/spec/has_helpers/service_trust/key_spec.rb +52 -0
- data/spec/has_helpers/service_trust/rake_tasks_spec.rb +58 -0
- data/spec/has_helpers/service_trust/rate_limiter_spec.rb +31 -0
- data/spec/has_helpers/service_trust/replay_cache_spec.rb +29 -0
- data/spec/has_helpers/service_trust/signer_verifier_spec.rb +159 -0
- data/spec/has_helpers/service_trust/smoke_spec.rb +216 -0
- data/spec/has_helpers/service_trust/support.rb +121 -0
- data/spec/has_helpers/service_trust/test_module_spec.rb +39 -0
- data/spec/has_helpers/service_trust/verify_middleware_spec.rb +82 -0
- data/spec/helpers/application_spec.rb +155 -0
- data/spec/importers/cards/importer_spec.rb +861 -0
- data/spec/internal/app/assets/config/manifest.js +0 -0
- data/spec/internal/app/constants/cat_egory.rb +33 -0
- data/spec/internal/app/constants/color.rb +19 -0
- data/spec/internal/app/constants/exclude_group_nil_constant.rb +5 -0
- data/spec/internal/app/constants/foo.rb +6 -0
- data/spec/internal/app/constants/fruit.rb +3 -0
- data/spec/internal/app/constants/generic_group_example.rb +12 -0
- data/spec/internal/app/constants/my_constant.rb +4 -0
- data/spec/internal/app/constants/product.rb +3 -0
- data/spec/internal/app/constants/shirt_size.rb +18 -0
- data/spec/internal/app/constants/simple_option.rb +14 -0
- data/spec/internal/app/constants/status.rb +5 -0
- data/spec/internal/app/constructors/organization_constructor.rb +4 -0
- data/spec/internal/app/controllers/application_controller.rb +27 -0
- data/spec/internal/app/controllers/search_extensions.rb +3 -0
- data/spec/internal/app/indices/advisor_index.rb +35 -0
- data/spec/internal/app/indices/contract_index.rb +52 -0
- data/spec/internal/app/indices/firm_index.rb +16 -0
- data/spec/internal/app/indices/policy_index.rb +20 -0
- data/spec/internal/app/models/advisor.rb +24 -0
- data/spec/internal/app/models/agency.rb +3 -0
- data/spec/internal/app/models/anonymous_coward.rb +5 -0
- data/spec/internal/app/models/another_event.rb +2 -0
- data/spec/internal/app/models/appointment.rb +3 -0
- data/spec/internal/app/models/attachment.rb +10 -0
- data/spec/internal/app/models/basic_schedule.rb +6 -0
- data/spec/internal/app/models/beneficiary.rb +6 -0
- data/spec/internal/app/models/client.rb +5 -0
- data/spec/internal/app/models/contract.rb +9 -0
- data/spec/internal/app/models/demographic.rb +4 -0
- data/spec/internal/app/models/division.rb +3 -0
- data/spec/internal/app/models/event.rb +10 -0
- data/spec/internal/app/models/event_template.rb +1 -0
- data/spec/internal/app/models/firm.rb +18 -0
- data/spec/internal/app/models/has_audits/audit.rb +15 -0
- data/spec/internal/app/models/import.rb +7 -0
- data/spec/internal/app/models/meetup.rb +8 -0
- data/spec/internal/app/models/organization.rb +17 -0
- data/spec/internal/app/models/organization_event.rb +5 -0
- data/spec/internal/app/models/policy.rb +16 -0
- data/spec/internal/app/models/policy_holder.rb +7 -0
- data/spec/internal/app/models/policy_note.rb +8 -0
- data/spec/internal/app/models/project.rb +3 -0
- data/spec/internal/app/models/read_only_value.rb +8 -0
- data/spec/internal/app/models/schedule.rb +12 -0
- data/spec/internal/app/models/template.rb +9 -0
- data/spec/internal/app/models/user.rb +31 -0
- data/spec/internal/app/models/user_organization.rb +17 -0
- data/spec/internal/app/views/has_lists/lists/_table.html.erb +1 -0
- data/spec/internal/config/database-standard.yml +24 -0
- data/spec/internal/config/initializers/resources.rb +19 -0
- data/spec/internal/config/routes.rb +19 -0
- data/spec/internal/config/storage.yml +3 -0
- data/spec/internal/db/good_job_schema.rb +141 -0
- data/spec/internal/db/schema.rb +334 -0
- data/spec/internal/log/.gitignore +1 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/lib/flattener/base_spec.rb +93 -0
- data/spec/lib/flattener/column/types_spec.rb +65 -0
- data/spec/lib/has_helpers/active_record/base_spec.rb +53 -0
- data/spec/lib/has_helpers/active_record/date_range_spec.rb +498 -0
- data/spec/lib/has_helpers/active_record/lookup_model_spec.rb +408 -0
- data/spec/lib/has_helpers/active_record/nested_resource_spec.rb +43 -0
- data/spec/lib/has_helpers/app/command/reports/generator_specs.rb +887 -0
- data/spec/lib/has_helpers/app/command_spec.rb +117 -0
- data/spec/lib/has_helpers/app/support/mocks/graphql_reports_helpers.rb +96 -0
- data/spec/lib/has_helpers/app/support/mocks/reports_api_mock.rb +47 -0
- data/spec/lib/has_helpers/attributes_spec.rb +220 -0
- data/spec/lib/has_helpers/aws_spec.rb +126 -0
- data/spec/lib/has_helpers/concerns/hydrate_concern_spec.rb +473 -0
- data/spec/lib/has_helpers/constant/definition_spec.rb +128 -0
- data/spec/lib/has_helpers/constant_spec.rb +432 -0
- data/spec/lib/has_helpers/core_ext/array_spec.rb +22 -0
- data/spec/lib/has_helpers/core_ext/date/infinity_spec.rb +67 -0
- data/spec/lib/has_helpers/core_ext/date_spec.rb +27 -0
- data/spec/lib/has_helpers/core_ext/false_class_spec.rb +7 -0
- data/spec/lib/has_helpers/core_ext/float_spec.rb +9 -0
- data/spec/lib/has_helpers/core_ext/hash_spec.rb +48 -0
- data/spec/lib/has_helpers/core_ext/integer_spec.rb +9 -0
- data/spec/lib/has_helpers/core_ext/nil_class_spec.rb +17 -0
- data/spec/lib/has_helpers/core_ext/object_spec.rb +54 -0
- data/spec/lib/has_helpers/core_ext/proc_spec.rb +24 -0
- data/spec/lib/has_helpers/core_ext/string_spec.rb +154 -0
- data/spec/lib/has_helpers/core_ext/true_class_spec.rb +7 -0
- data/spec/lib/has_helpers/data_migration/base_spec.rb +470 -0
- data/spec/lib/has_helpers/data_migration/large_worker_spec.rb +34 -0
- data/spec/lib/has_helpers/data_migration/master_worker_spec.rb +51 -0
- data/spec/lib/has_helpers/data_migration/migrator_spec.rb +113 -0
- data/spec/lib/has_helpers/data_migration/model_spec.rb +52 -0
- data/spec/lib/has_helpers/data_migration/small_worker_spec.rb +34 -0
- data/spec/lib/has_helpers/good_job/notification_alert_cleanup_worker_spec.rb +89 -0
- data/spec/lib/has_helpers/hash_accessors_spec.rb +66 -0
- data/spec/lib/has_helpers/index_spec.rb +442 -0
- data/spec/lib/has_helpers/lazy_config_spec.rb +31 -0
- data/spec/lib/has_helpers/organization_merge_spec.rb +88 -0
- data/spec/lib/has_helpers/resource_importer_spec.rb +119 -0
- data/spec/lib/has_helpers/rspec_spec.rb +16 -0
- data/spec/lib/has_helpers/search/provider_spec.rb +26 -0
- data/spec/lib/has_helpers/search/search_utils_spec.rb +134 -0
- data/spec/lib/has_helpers/sentry/graphql_trace_spec.rb +140 -0
- data/spec/lib/has_helpers/ui_attributes_spec.rb +42 -0
- data/spec/lib/has_helpers/utils/action_spec.rb +49 -0
- data/spec/lib/has_helpers/utils/alert_spec.rb +33 -0
- data/spec/lib/has_helpers/utils/dataset_spec.rb +10 -0
- data/spec/lib/has_helpers/utils/icon_spec.rb +23 -0
- data/spec/lib/has_helpers/utils/input_spec.rb +40 -0
- data/spec/lib/has_helpers/utils/log_notifier_spec.rb +25 -0
- data/spec/lib/has_helpers/utils/render_object_spec.rb +17 -0
- data/spec/lib/has_helpers/utils/s3_utils_spec.rb +78 -0
- data/spec/lib/has_helpers/utils/service_spec.rb +79 -0
- data/spec/lib/has_helpers/utils/slack_notifier_spec.rb +70 -0
- data/spec/lib/has_helpers/utils/user_restrictions_spec.rb +343 -0
- data/spec/lib/hq/structure/inserts_spec.rb +152 -0
- data/spec/lib/hq/structure_spec.rb +12 -0
- data/spec/models/cards/base_spec.rb +149 -0
- data/spec/models/cards/card_definition_resource_spec.rb +103 -0
- data/spec/models/cards/card_definition_spec.rb +50 -0
- data/spec/models/cards/card_field_spec.rb +46 -0
- data/spec/models/cards/field_builder_spec.rb +318 -0
- data/spec/models/cards/registry_spec.rb +147 -0
- data/spec/models/cards/role_card_field_spec.rb +111 -0
- data/spec/models/cards/role_resource_card_spec.rb +112 -0
- data/spec/models/has_helpers/master_record_spec.rb +20 -0
- data/spec/models/has_helpers/user_organization_spec.rb +28 -0
- data/spec/models/has_helpers/user_session_spec.rb +16 -0
- data/spec/presenters/base_presenter_spec.rb +166 -0
- data/spec/rails_helper.rb +119 -0
- data/spec/requests/has_helpers/factory_controller_spec.rb +159 -0
- data/spec/requests/has_helpers/health_check_controller_spec.rb +37 -0
- data/spec/scenarios/empty_setup.rb +6 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/has_helpers/database_helpers.rb +12 -0
- data/spec/utils/sync_utils_spec.rb +233 -0
- data/spec/workers/goodjob/elasticsearch_process_batch_spec.rb +94 -0
- data/spec/workers/goodjob/elasticsearch_process_change_logs_master_worker_spec.rb +40 -0
- data/spec/workers/goodjob/elasticsearch_process_change_logs_worker_spec.rb +82 -0
- data/spec/workers/goodjob/elasticsearch_process_queue_spec.rb +89 -0
- data/spec/workers/goodjob/elasticsearch_reindex_spec.rb +49 -0
- metadata +1593 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
class DBOperations::CleanStatsWorker < HasUtils::GoodJob::BaseWorker
|
|
5
|
+
include HasHelpers::DefaultWorker
|
|
6
|
+
include HasHelpers::RedisConfigurable
|
|
7
|
+
|
|
8
|
+
queue_as :db_clean
|
|
9
|
+
|
|
10
|
+
AGE_LIMIT_STRING = "1 month"
|
|
11
|
+
|
|
12
|
+
config_defaults(
|
|
13
|
+
db_operation_stats_resume_enabled: true # means db_operations_stats_resumes was created and is used to reporting purposes
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def perform
|
|
17
|
+
::Rails.logger.info "Removing db_operations_stats older than #{AGE_LIMIT_STRING}...."
|
|
18
|
+
|
|
19
|
+
total_removed = 0
|
|
20
|
+
|
|
21
|
+
loop do
|
|
22
|
+
num_removed = ::HasHelpers::DBOperations::Operations.with_advisory_lock("'db_operations_stats'::regclass::integer") do |connection|
|
|
23
|
+
connection.exec_delete <<-END_OF_SQL
|
|
24
|
+
DELETE FROM db_operations_stats
|
|
25
|
+
WHERE created_at <= now() - interval '#{AGE_LIMIT_STRING}'
|
|
26
|
+
END_OF_SQL
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
break if num_removed == 0
|
|
30
|
+
total_removed += num_removed
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
::Rails.logger.info "Removed #{total_removed} operation stats."
|
|
34
|
+
|
|
35
|
+
if config.db_operation_stats_resume_enabled
|
|
36
|
+
HasHelpers::DBOperations::UpdateOperationsStatsResumeWorker.perform_later
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
delegate :config, to: :class
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
class DBOperations::HelperWorker < HasUtils::GoodJob::BaseWorker
|
|
5
|
+
include HasHelpers::DefaultWorker
|
|
6
|
+
|
|
7
|
+
queue_as :pending_db_ops
|
|
8
|
+
|
|
9
|
+
MAIN_KLASS = DBOperations::MainWorker
|
|
10
|
+
|
|
11
|
+
# queue_type is mandatory and could be one of the following:
|
|
12
|
+
# "fast" runs the worker for the fast queries queue
|
|
13
|
+
# "slow" runs the worker for the slow queries queue
|
|
14
|
+
def perform(queue_type)
|
|
15
|
+
return if HasHelpers::Feature.active?(:old_pending_db_ops)
|
|
16
|
+
|
|
17
|
+
if ::HasHelpers::DBOperations::Operations.paused?
|
|
18
|
+
::Rails.logger.info "DBOperations::HelperWorker skip because paused"
|
|
19
|
+
return
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Use appropriate lock and queue names depending on the queue type
|
|
23
|
+
lock_key, queue_name, is_fast = determine_queue(queue_type)
|
|
24
|
+
|
|
25
|
+
# Check if another worker is running for this queue; if so, exit early
|
|
26
|
+
return if redis.get(lock_key) == "true"
|
|
27
|
+
|
|
28
|
+
# Set a lock in Redis to indicate that this worker is running, with an expiration time
|
|
29
|
+
redis.set(lock_key, "true", ex: MAIN_KLASS.config.helper_worker_lock_expiration)
|
|
30
|
+
|
|
31
|
+
# Start renewing the lock in a separate thread (for long-running queries)
|
|
32
|
+
lock_renewal_thread = Thread.new { renew_lock_periodically(lock_key) }
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
# Retrieve and remove a batch of jobs from Redis in an atomic operation
|
|
36
|
+
ids = redis.zpopmin(queue_name, MAIN_KLASS.config.helper_worker_batch_size).map { |id, _score| id }
|
|
37
|
+
|
|
38
|
+
return if ids.empty? # If no jobs are left in Redis, exit
|
|
39
|
+
|
|
40
|
+
triggered_slow_query_worker = false
|
|
41
|
+
|
|
42
|
+
ids.each do |id|
|
|
43
|
+
job = HasHelpers::PendingDBOperation.find_by(id: id)
|
|
44
|
+
begin
|
|
45
|
+
# Process the query (with timeout for fast queries)
|
|
46
|
+
execute_query(job, is_fast) if job
|
|
47
|
+
rescue ::PsqlHq::StatementTimeout
|
|
48
|
+
if is_fast
|
|
49
|
+
# If a query timeout occurs, move it to the slow queue
|
|
50
|
+
mark_as_slow(job)
|
|
51
|
+
|
|
52
|
+
# Trigger the slow worker if needed and only once for the whole batch
|
|
53
|
+
if redis.zcard(MAIN_KLASS::SLOW_QUEUE) > 0 && !triggered_slow_query_worker
|
|
54
|
+
::HasHelpers::DBOperations::HelperWorker.perform_later("slow")
|
|
55
|
+
triggered_slow_query_worker = true
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Re-enqueue this worker for fast or slow queue if more jobs remain
|
|
62
|
+
::HasHelpers::DBOperations::HelperWorker.perform_later(queue_type) if redis.zcard(queue_name) > 0
|
|
63
|
+
ensure
|
|
64
|
+
# Stop lock renewal and clear the lock in Redis when the worker finishes
|
|
65
|
+
lock_renewal_thread.kill
|
|
66
|
+
redis.del(lock_key)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Helper method to determine queue type, name and lock key
|
|
71
|
+
def determine_queue(queue_type)
|
|
72
|
+
if queue_type == "fast"
|
|
73
|
+
[MAIN_KLASS::FAST_WORKER_LOCK_KEY, MAIN_KLASS::FAST_QUEUE, true]
|
|
74
|
+
else
|
|
75
|
+
[MAIN_KLASS::SLOW_WORKER_LOCK_KEY, MAIN_KLASS::SLOW_QUEUE, false]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Helper method to execute the query, we establish a timeout for fast queues
|
|
80
|
+
# for slow queues we just execute the query without timeout, since we don't know how much they might take
|
|
81
|
+
# The idea is that slow queries should be a rare case and not a common scenario, so we let them be
|
|
82
|
+
# until someone fix them
|
|
83
|
+
def execute_query(job, is_fast)
|
|
84
|
+
::PsqlHq::TimeoutRunner.within(timeout: is_fast ? MAIN_KLASS.config.helper_worker_query_timeout_fast : MAIN_KLASS.config.helper_worker_query_timeout_slow) do |connection|
|
|
85
|
+
job.execute(connection: connection)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Mark the query as slow
|
|
90
|
+
def mark_as_slow(job)
|
|
91
|
+
remove_job_from_queue(MAIN_KLASS::FAST_QUEUE, job.id)
|
|
92
|
+
job.defer_processing # defer processing so next time is going to be enqueued in the slow queue
|
|
93
|
+
job.is_slow = true
|
|
94
|
+
job.save
|
|
95
|
+
log_slow_query(job)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Log slow query details for later analysis
|
|
99
|
+
def log_slow_query(job)
|
|
100
|
+
time = Time.zone.now
|
|
101
|
+
|
|
102
|
+
# TODO fix this when this is implemented in agencies
|
|
103
|
+
# ex: agencies has its own stat class and field names are different
|
|
104
|
+
stat = ::HasHelpers::Stat.new
|
|
105
|
+
stat.name = job.relation_name
|
|
106
|
+
stat.maintype = "pending_db_ops"
|
|
107
|
+
stat.subtype = "slow"
|
|
108
|
+
stat.data = { id: job.id, query: job.sql, foreign_key: job.foreign_key_value }
|
|
109
|
+
stat.created_at = time
|
|
110
|
+
stat.updated_at = time
|
|
111
|
+
stat.save!
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Remove a job from Redis queue
|
|
115
|
+
def remove_job_from_queue(queue_name, job_id)
|
|
116
|
+
redis.zrem(queue_name, job_id)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Renew the lock periodically (every 4 minutes)
|
|
120
|
+
def renew_lock_periodically(lock_key)
|
|
121
|
+
loop do
|
|
122
|
+
sleep 1.minute
|
|
123
|
+
redis.expire(lock_key, MAIN_KLASS.config.helper_worker_lock_expiration) if redis.get(lock_key)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def redis
|
|
128
|
+
RedisConf.current
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
class DBOperations::MainWorker < HasUtils::GoodJob::BaseWorker
|
|
5
|
+
include HasHelpers::DefaultWorker
|
|
6
|
+
include HasHelpers::RedisConfigurable
|
|
7
|
+
|
|
8
|
+
queue_as :pending_db_ops
|
|
9
|
+
|
|
10
|
+
FAST_QUEUE = "pending_db_ops_fast" # The queue used for fast/usual jobs
|
|
11
|
+
SLOW_QUEUE = "pending_db_ops_slow" # The queue used for jobs that were marked as slow
|
|
12
|
+
FAST_WORKER_LOCK_KEY = "pending_db_ops_fast_worker" # The lock key for the worker that executes jobs in the fast queue
|
|
13
|
+
SLOW_WORKER_LOCK_KEY = "pending_db_ops_slow_worker" # The lock key for the worker that executes jobs in the slow queue
|
|
14
|
+
MAIN_WORKER_LOCK_KEY = "pending_db_ops_main_worker" # The lock key for the main worker
|
|
15
|
+
|
|
16
|
+
config_defaults(
|
|
17
|
+
enqueue_batch_size: 1000, # How many jobs the main worker enqueues each time
|
|
18
|
+
max_queue_size: 3000, # The max number of jobs the queue will hold
|
|
19
|
+
max_enqueue_time: 10.minutes, # How long a job is going to be in the queue before considering it stucked and re-enqueue it
|
|
20
|
+
helper_worker_lock_expiration: 5.minutes, # How long each worker holds the key (to avoid running multiple workers of the same kind at the same time)
|
|
21
|
+
helper_worker_batch_size: 1000, # Batch size for helper workers
|
|
22
|
+
helper_worker_query_timeout_fast: 1.second, # Max time we'll allow normal queries to execute
|
|
23
|
+
helper_worker_query_timeout_slow: 5.minutes, # Max time we'll allow slow queries to execute
|
|
24
|
+
# If there are no more jobs to be enqueued or if the queue is full, the main worker is going to slee
|
|
25
|
+
# for `main_worker_sleep` long before trying to search for more pending db ops, as long as no more than
|
|
26
|
+
# `main_worker_lifespan` time has elapsed, in which case the worker is going to be finished until it
|
|
27
|
+
# is re-enqueued by the sidekiq worker in the next minute.
|
|
28
|
+
# The reason behind doing this is that sometimes the main worker can't enqueue more jobs and if it finishes,
|
|
29
|
+
# it won't be executed until the next minute (by the sidekiq scheduler). By doing this we try to reduce the
|
|
30
|
+
# number of pending db ops that get stack before being enqueued for processing
|
|
31
|
+
main_worker_sleep: 10.seconds,
|
|
32
|
+
main_worker_lifespan: 3.minutes
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def perform
|
|
36
|
+
return if HasHelpers::Feature.active?(:old_pending_db_ops)
|
|
37
|
+
|
|
38
|
+
if ::HasHelpers::DBOperations::Operations.paused?
|
|
39
|
+
::Rails.logger.info "DBOperations::MainWorker skip because paused"
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
return if main_worker_locked?
|
|
45
|
+
started_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
46
|
+
|
|
47
|
+
loop do
|
|
48
|
+
lock_main_worker
|
|
49
|
+
main_process
|
|
50
|
+
|
|
51
|
+
ended_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
52
|
+
sleep(config.main_worker_sleep.seconds)
|
|
53
|
+
break if (ended_at - started_at) > config.main_worker_lifespan.seconds
|
|
54
|
+
break if ::HasHelpers::DBOperations::Operations.paused?
|
|
55
|
+
end
|
|
56
|
+
ensure
|
|
57
|
+
release_main_worker_lock
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def main_worker_locked?
|
|
62
|
+
redis.get(MAIN_WORKER_LOCK_KEY) == "true"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def lock_main_worker
|
|
66
|
+
if redis.get(MAIN_WORKER_LOCK_KEY) == "true"
|
|
67
|
+
redis.expire(MAIN_WORKER_LOCK_KEY, 1.minute)
|
|
68
|
+
else
|
|
69
|
+
redis.set(MAIN_WORKER_LOCK_KEY, "true", ex: 1.minute)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def release_main_worker_lock
|
|
74
|
+
redis.del(MAIN_WORKER_LOCK_KEY)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def main_process
|
|
78
|
+
# Recover jobs stuck in both fast and slow queues
|
|
79
|
+
recover_all_stuck_jobs
|
|
80
|
+
|
|
81
|
+
# Enqueue pending jobs in both fast and slow queues
|
|
82
|
+
enqueue_all_pending_jobs
|
|
83
|
+
|
|
84
|
+
# If there are jobs in the fast queue and no fast worker is running, trigger the fast worker
|
|
85
|
+
if redis.zcard(FAST_QUEUE) > 0 && !worker_running?(FAST_WORKER_LOCK_KEY)
|
|
86
|
+
::HasHelpers::DBOperations::HelperWorker.perform_later("fast")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# If there are jobs in the slow queue and no slow worker is running, trigger the slow worker
|
|
90
|
+
if redis.zcard(SLOW_QUEUE) > 0 && !worker_running?(SLOW_WORKER_LOCK_KEY)
|
|
91
|
+
::HasHelpers::DBOperations::HelperWorker.perform_later("slow")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def recover_all_stuck_jobs
|
|
96
|
+
recover_stuck_jobs(nil) # recover fast stuck queries
|
|
97
|
+
recover_stuck_jobs(true) # recover slow stuck queries
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Recover stuck jobs in the queue and re-enqueue them
|
|
101
|
+
def recover_stuck_jobs(is_slow)
|
|
102
|
+
queue_name = is_slow ? SLOW_QUEUE : FAST_QUEUE
|
|
103
|
+
current_queue_size = redis.zcard(queue_name)
|
|
104
|
+
return if current_queue_size >= config.max_queue_size
|
|
105
|
+
|
|
106
|
+
current_limit = [config.enqueue_batch_size, config.max_queue_size - current_queue_size].min
|
|
107
|
+
|
|
108
|
+
stuck_jobs_sql = HasHelpers::PendingDBOperation.where(HasHelpers::PendingDBOperation.arel_table[:enqueued_at].lt(Time.zone.now - config.max_enqueue_time.seconds)).where.not(enqueued_at: nil).where(is_slow: is_slow).limit(current_limit).to_sql
|
|
109
|
+
HasHelpers::PendingDBOperation.uncached do
|
|
110
|
+
stuck_jobs = HasHelpers::PendingDBOperation.find_by_sql(stuck_jobs_sql) # The reason behind doing this is to bypass ActiveRecord cache, I tried with just `uncached` but Rails was still caching the result
|
|
111
|
+
enqueue_jobs(stuck_jobs)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def enqueue_all_pending_jobs
|
|
116
|
+
enqueue_pending_jobs(nil) # enqueue fast queries
|
|
117
|
+
enqueue_pending_jobs(true) # enqueue slow queries
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Enqueue new jobs that have not been enqueued yet
|
|
121
|
+
def enqueue_pending_jobs(is_slow)
|
|
122
|
+
queue_name = is_slow ? SLOW_QUEUE : FAST_QUEUE
|
|
123
|
+
current_queue_size = redis.zcard(queue_name)
|
|
124
|
+
return if current_queue_size >= config.max_queue_size
|
|
125
|
+
|
|
126
|
+
current_limit = [config.enqueue_batch_size, config.max_queue_size - current_queue_size].min
|
|
127
|
+
|
|
128
|
+
pending_jobs_sql = HasHelpers::PendingDBOperation.where(enqueued_at: nil).where(is_slow: is_slow).order(:created_at).limit(current_limit).to_sql
|
|
129
|
+
HasHelpers::PendingDBOperation.uncached do
|
|
130
|
+
pending_jobs = HasHelpers::PendingDBOperation.find_by_sql(pending_jobs_sql) # The reason behind doing this is to bypass ActiveRecord cache, I tried with just `uncached` but Rails was still caching the result
|
|
131
|
+
enqueue_jobs(pending_jobs)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def enqueue_jobs(jobs)
|
|
136
|
+
jobs.each do |job|
|
|
137
|
+
break if ::HasHelpers::DBOperations::Operations.paused?
|
|
138
|
+
if job.is_slow
|
|
139
|
+
enqueue_job_in_redis(job, SLOW_QUEUE) # Enqueue slow jobs directly into the slow queue
|
|
140
|
+
else
|
|
141
|
+
enqueue_job_in_redis(job, FAST_QUEUE) # Enqueue regular jobs into the fast queue
|
|
142
|
+
end
|
|
143
|
+
job.update!(enqueued_at: Time.zone.now)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Helper method to enqueue a job into Redis
|
|
148
|
+
def enqueue_job_in_redis(job, queue_name)
|
|
149
|
+
redis.zadd(queue_name, job.created_at.to_f, job.id)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Check if the worker for the fast or slow queue is already running by looking at a Redis lock/flag with expiration
|
|
153
|
+
def worker_running?(lock_key)
|
|
154
|
+
lock_ttl = redis.ttl(lock_key)
|
|
155
|
+
lock_ttl > 0 # The lock is active if TTL (Time to Live) is positive
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def redis
|
|
159
|
+
RedisConf.current
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
delegate :config, to: :class
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Provides a variety of utilities related to DB operations:
|
|
4
|
+
# 1. Access to a shared logger
|
|
5
|
+
module HasHelpers
|
|
6
|
+
module DBOperations::Operations
|
|
7
|
+
MAX_PROCESSING_TIME = 5.minutes
|
|
8
|
+
PAUSED_KEY = "db_ops_paused"
|
|
9
|
+
PAUSE_TABLE_KEY_PREFIX = "db_ops_pause_table"
|
|
10
|
+
DEFAULT_PAUSE_TABLE_DURATION_SECONDS = 1.day.to_i
|
|
11
|
+
|
|
12
|
+
def self.run_one_db_operation(id)
|
|
13
|
+
::HasHelpers::DBOperations::Operations.with_advisory_lock_2("'pending_db_operations'::regclass::integer", id) do |connection|
|
|
14
|
+
connection.execute("SELECT run_one_db_operation(#{id})")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.enqueue_ops(except_for: nil)
|
|
19
|
+
pending_db_ops = HasHelpers::PendingDBOperation.where(enqueued_at: nil).order(:created_at).limit(1_000).select(:id)
|
|
20
|
+
if except_for.present?
|
|
21
|
+
pending_db_ops = pending_db_ops.where.not(relation_name: except_for)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
pending_db_ops_sql = pending_db_ops.to_sql
|
|
25
|
+
Enumerator.new do |yielder|
|
|
26
|
+
holdstart = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
27
|
+
|
|
28
|
+
loop do
|
|
29
|
+
enqueued_db_ops = HasHelpers::PendingDBOperation.uncached do
|
|
30
|
+
HasHelpers::PendingDBOperation.find_by_sql <<-SQL
|
|
31
|
+
WITH updated_rows AS (
|
|
32
|
+
UPDATE pending_db_operations
|
|
33
|
+
SET enqueued_at = now() at time zone 'utc'
|
|
34
|
+
WHERE id IN (#{pending_db_ops_sql})
|
|
35
|
+
RETURNING id
|
|
36
|
+
)
|
|
37
|
+
SELECT *
|
|
38
|
+
FROM pending_db_operations
|
|
39
|
+
INNER JOIN updated_rows ON updated_rows.id = pending_db_operations.id
|
|
40
|
+
SQL
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if enqueued_db_ops.present?
|
|
44
|
+
yielder << enqueued_db_ops
|
|
45
|
+
else
|
|
46
|
+
break
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
endt = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
50
|
+
break if (endt - holdstart) > MAX_PROCESSING_TIME
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.defer_processing(id)
|
|
56
|
+
HasHelpers::PendingDBOperation.defer_processing(id)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
## overrides to provide default connection pool
|
|
60
|
+
def self.with_advisory_lock(key, connection_pool: self.connection_pool, &block)
|
|
61
|
+
::PsqlHq::Utils.with_advisory_lock(key, connection_pool: connection_pool, &block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.with_advisory_lock_2(key1, key2, connection_pool: self.connection_pool, &block) # rubocop:disable Naming/VariableNumber
|
|
65
|
+
::PsqlHq::Utils.with_advisory_lock_2(key1, key2, connection_pool: connection_pool, &block)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.with_advisory_xact_lock(key, connection_pool: self.connection_pool, &block)
|
|
69
|
+
::PsqlHq::Utils.with_advisory_xact_lock(key, connection_pool: connection_pool, &block)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.with_advisory_xact_lock_2(key1, key2, connection_pool: self.connection_pool, &block) # rubocop:disable Naming/VariableNumber
|
|
73
|
+
::PsqlHq::Utils.with_advisory_xact_lock_2(key1, key2, connection_pool: connection_pool, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##### Pause / Unpause #####
|
|
77
|
+
def self.pause(duration = 24.hours.to_i)
|
|
78
|
+
::HasUtils::Env.run_on_environment excluded: [::HasUtils::Env::TEST] do
|
|
79
|
+
RedisConf.current.setex(PAUSED_KEY, duration, true)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.resume
|
|
84
|
+
RedisConf.current.del(PAUSED_KEY)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.paused?
|
|
88
|
+
RedisConf.current.get(PAUSED_KEY).present?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Use the master connection, otherwise this will break when running with crunchy-proxy.
|
|
92
|
+
# crunchy-proxy can not recongize that a function has writes in it unless you add it to an exception list.
|
|
93
|
+
def self.connection_pool
|
|
94
|
+
HasHelpers::MasterRecord.connection_pool
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##### Temporary Table Pausing #####
|
|
98
|
+
|
|
99
|
+
# Use to indicate that we want to stop processing this table for the
|
|
100
|
+
# duration indicated. If no duration is specified, defaults to
|
|
101
|
+
# DEFAULT_PAUSE_TABLE_DURATION_SECONDS. Note that calling this overwrites any
|
|
102
|
+
# previous call to stop processing this table, even if the previous call's
|
|
103
|
+
# duration has not expired.
|
|
104
|
+
def self.pause_table(table_name, duration = DEFAULT_PAUSE_TABLE_DURATION_SECONDS)
|
|
105
|
+
::HasUtils::Env.run_on_environment excluded: [::HasUtils::Env::TEST] do
|
|
106
|
+
RedisConf.current.setex(pause_table_redis_key(table_name), duration, true)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns a boolean indicating if we are pausing processing of this table.
|
|
111
|
+
def self.table_paused?(table_name)
|
|
112
|
+
redis_key = pause_table_redis_key(table_name)
|
|
113
|
+
RedisConf.current.get(redis_key).present?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Cancels any pausing previously set for this table.
|
|
117
|
+
def self.resume_table(table_name)
|
|
118
|
+
RedisConf.current.del(pause_table_redis_key(table_name))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.resume_all_tables
|
|
122
|
+
keys = RedisConf.current.keys("#{PAUSE_TABLE_KEY_PREFIX}::*")
|
|
123
|
+
RedisConf.current.del(keys) if keys.present?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.pause_table_redis_key(table_name)
|
|
127
|
+
"#{PAUSE_TABLE_KEY_PREFIX}::#{table_name}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.disabled_tables
|
|
131
|
+
RedisConf.current.keys("#{PAUSE_TABLE_KEY_PREFIX}::*").map { |k| k.sub("#{PAUSE_TABLE_KEY_PREFIX}::", "") }
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
class DBOperations::UpdateOperationsStatsResumeWorker < HasUtils::GoodJob::BaseWorker
|
|
5
|
+
include HasHelpers::DefaultWorker
|
|
6
|
+
|
|
7
|
+
queue_as :db_clean
|
|
8
|
+
|
|
9
|
+
def perform
|
|
10
|
+
::Rails.logger.info "Truncate db_operations_stats_resumes."
|
|
11
|
+
|
|
12
|
+
ActiveRecord::Base.connection.execute <<-END_OF_SQL
|
|
13
|
+
TRUNCATE db_operations_stats_resumes;
|
|
14
|
+
END_OF_SQL
|
|
15
|
+
|
|
16
|
+
::Rails.logger.info "Start updating db_operations_stats_resumes"
|
|
17
|
+
|
|
18
|
+
ActiveRecord::Base.connection.execute <<-END_OF_SQL
|
|
19
|
+
INSERT INTO db_operations_stats_resumes
|
|
20
|
+
SELECT relation_name || (executed_sql_json -> 'sql')::TEXT AS id,
|
|
21
|
+
relation_name,
|
|
22
|
+
MAX(created_at) AS last_created_at,
|
|
23
|
+
SUM(execute_duration) AS sum_duration,
|
|
24
|
+
COUNT(relation_name) AS count_calls,
|
|
25
|
+
executed_sql_json -> 'sql' AS executed_sql,
|
|
26
|
+
MAX(execute_duration) AS max_duration
|
|
27
|
+
FROM db_operations_stats
|
|
28
|
+
GROUP BY relation_name,
|
|
29
|
+
executed_sql_json -> 'sql';
|
|
30
|
+
END_OF_SQL
|
|
31
|
+
|
|
32
|
+
::Rails.logger.info "Updated db_operations_stats_resumes"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
module DefaultWorker
|
|
5
|
+
def self.included(base_class)
|
|
6
|
+
base_class.prepend InstanceMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module InstanceMethods
|
|
10
|
+
def perform(...)
|
|
11
|
+
HasHelpers::MasterRecord.without_pgpool do
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
module GoodJob
|
|
5
|
+
class NotificationAlertCleanupWorker < HasUtils::GoodJob::BaseWorker
|
|
6
|
+
queue_as :default
|
|
7
|
+
|
|
8
|
+
def perform
|
|
9
|
+
cleanup_old_alerts
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def cleanup_old_alerts
|
|
15
|
+
cutoff_date = 1.month.ago
|
|
16
|
+
|
|
17
|
+
Rails.logger.info("Starting cleanup of notification alerts older than #{cutoff_date}")
|
|
18
|
+
|
|
19
|
+
old_alerts = HasHelpers::NotificationAlert.where("created_at < ?", cutoff_date)
|
|
20
|
+
count = old_alerts.count
|
|
21
|
+
|
|
22
|
+
if count > 0
|
|
23
|
+
Rails.logger.info("Found #{count} notification alerts to clean up")
|
|
24
|
+
|
|
25
|
+
# batches to avoid memory issues
|
|
26
|
+
old_alerts.find_in_batches(batch_size: 100) do |batch|
|
|
27
|
+
batch_ids = batch.map(&:id)
|
|
28
|
+
HasHelpers::NotificationAlert.where(id: batch_ids).delete_all
|
|
29
|
+
Rails.logger.info("Deleted batch of #{batch.size} notification alerts")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Rails.logger.info("Successfully cleaned up #{count} old notification alerts")
|
|
33
|
+
else
|
|
34
|
+
Rails.logger.info("No old notification alerts found to clean up")
|
|
35
|
+
end
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
Rails.logger.error("Error cleaning up notification alerts: #{e.message}")
|
|
38
|
+
Rails.logger.error(e.backtrace.join("\n"))
|
|
39
|
+
raise e
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HasHelpers
|
|
4
|
+
module ServiceTrust
|
|
5
|
+
class AuditLogCleanupWorker < HasUtils::GoodJob::BaseWorker
|
|
6
|
+
queue_as :default
|
|
7
|
+
|
|
8
|
+
def perform
|
|
9
|
+
cutoff = Time.current - HasHelpers::ServiceTrust.config.audit_log_retention
|
|
10
|
+
loop do
|
|
11
|
+
ids = AuditLog.where("occurred_at < ?", cutoff).limit(10_000).pluck(:id)
|
|
12
|
+
break if ids.empty?
|
|
13
|
+
|
|
14
|
+
AuditLog.where(id: ids).delete_all
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|