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.
Files changed (748) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +10 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.tekton/Chart.yaml +14 -0
  8. data/.tekton/templates/pipelinerun.yaml +44 -0
  9. data/.tekton/values-main.yaml +53 -0
  10. data/.tekton/values-pr.yaml +40 -0
  11. data/.tekton/values.yaml +17 -0
  12. data/.tool-versions +1 -0
  13. data/CHANGELOG.md +204 -0
  14. data/Gemfile +25 -0
  15. data/README.md +76 -0
  16. data/Rakefile +46 -0
  17. data/app/api/has_helpers/rack_api.rb +116 -0
  18. data/app/api/has_helpers/search_api.rb +173 -0
  19. data/app/assets/stylesheets/has_helpers/base.scss +5 -0
  20. data/app/assets/stylesheets/has_helpers/color_palette.scss +33 -0
  21. data/app/assets/stylesheets/has_helpers/color_palettes/default.scss +11 -0
  22. data/app/assets/stylesheets/has_helpers/components/dataset.scss +43 -0
  23. data/app/assets/stylesheets/has_helpers/mixins.scss +149 -0
  24. data/app/commands/has_helpers/cards/available_cards_command.rb +98 -0
  25. data/app/commands/has_helpers/cards/card_data_command.rb +1062 -0
  26. data/app/commands/reports/base_options.rb +79 -0
  27. data/app/commands/reports/belongs_to_options.rb +178 -0
  28. data/app/commands/reports/constant_options.rb +66 -0
  29. data/app/commands/reports/external_graphql_client.rb +116 -0
  30. data/app/commands/reports/fill_dates.rb +65 -0
  31. data/app/commands/reports/filter_option_generator.rb +186 -0
  32. data/app/commands/reports/generator.rb +310 -0
  33. data/app/commands/reports/has_many_options.rb +105 -0
  34. data/app/commands/reports/importer.rb +132 -0
  35. data/app/commands/reports/nested_attribute_options.rb +134 -0
  36. data/app/constants/color.rb +9 -0
  37. data/app/constants/file_format.rb +12 -0
  38. data/app/constants/has_helpers/cards/card_custom_field.rb +12 -0
  39. data/app/constants/has_helpers/cards/card_data_type.rb +11 -0
  40. data/app/constants/has_helpers/cards/card_identifier.rb +10 -0
  41. data/app/constants/has_helpers/cards/card_layout_type.rb +11 -0
  42. data/app/constants/has_helpers/cards/card_variant_type.rb +12 -0
  43. data/app/constants/has_helpers/link_type.rb +10 -0
  44. data/app/constants/has_helpers/notification_alert_status.rb +14 -0
  45. data/app/constants/has_helpers/notification_alert_type.rb +10 -0
  46. data/app/constants/has_helpers/operation.rb +11 -0
  47. data/app/constants/has_helpers/resource_type.rb +25 -0
  48. data/app/constants/icon.rb +22 -0
  49. data/app/constants/logical_operator.rb +7 -0
  50. data/app/constants/option.rb +10 -0
  51. data/app/constants/time_zone.rb +12 -0
  52. data/app/constructors/has_helpers/base_constructor.rb +62 -0
  53. data/app/controllers/concerns/has_helpers/service_trust/authenticated_as_service.rb +51 -0
  54. data/app/controllers/concerns/has_helpers/service_trust/graphql_authentication.rb +57 -0
  55. data/app/controllers/has_helpers/controller.rb +63 -0
  56. data/app/controllers/has_helpers/factory_controller.rb +261 -0
  57. data/app/controllers/has_helpers/graphql_extensions.rb +83 -0
  58. data/app/controllers/has_helpers/health_check_controller.rb +46 -0
  59. data/app/controllers/has_helpers/search_extensions.rb +92 -0
  60. data/app/controllers/has_helpers/service_trust/jwks_controller.rb +20 -0
  61. data/app/controllers/has_helpers/xlsx_export.rb +115 -0
  62. data/app/controllers/search_extensions.rb +5 -0
  63. data/app/graphql/has_helpers/base_type.rb +13 -0
  64. data/app/graphql/has_helpers/base_union.rb +9 -0
  65. data/app/graphql/has_helpers/enums/resource_enum.rb +24 -0
  66. data/app/graphql/has_helpers/middleware/application_access.rb +26 -0
  67. data/app/graphql/has_helpers/mutations/base.rb +27 -0
  68. data/app/graphql/has_helpers/mutations/external_data_sync.rb +72 -0
  69. data/app/graphql/has_helpers/mutations/mark_individual_alert_read.rb +31 -0
  70. data/app/graphql/has_helpers/mutations/mark_notifications_read.rb +50 -0
  71. data/app/graphql/has_helpers/mutations/toggle_favorite.rb +39 -0
  72. data/app/graphql/has_helpers/resolvers/app_nav.rb +107 -0
  73. data/app/graphql/has_helpers/resolvers/base.rb +27 -0
  74. data/app/graphql/has_helpers/resolvers/cards/available_cards.rb +31 -0
  75. data/app/graphql/has_helpers/resolvers/cards/card_data.rb +74 -0
  76. data/app/graphql/has_helpers/resolvers/cards/hover_card_data.rb +153 -0
  77. data/app/graphql/has_helpers/resolvers/favorite.rb +62 -0
  78. data/app/graphql/has_helpers/resolvers/internal/roles.rb +54 -0
  79. data/app/graphql/has_helpers/resolvers/is_favorite.rb +24 -0
  80. data/app/graphql/has_helpers/resolvers/list_notification_alerts.rb +47 -0
  81. data/app/graphql/has_helpers/resolvers/lookup.rb +36 -0
  82. data/app/graphql/has_helpers/resolvers/recently_viewed.rb +54 -0
  83. data/app/graphql/has_helpers/resolvers/resource_tab.rb +22 -0
  84. data/app/graphql/has_helpers/resolvers/search.rb +18 -0
  85. data/app/graphql/has_helpers/resolvers/search_query.rb +38 -0
  86. data/app/graphql/has_helpers/resolvers/user_application_order.rb +35 -0
  87. data/app/graphql/has_helpers/resources/organization_option_resource.rb +28 -0
  88. data/app/graphql/has_helpers/resources/organization_resource_resource.rb +18 -0
  89. data/app/graphql/has_helpers/resources/resource_group_resource.rb +10 -0
  90. data/app/graphql/has_helpers/resources/resource_resource.rb +21 -0
  91. data/app/graphql/has_helpers/resources/user_role_resource.rb +9 -0
  92. data/app/graphql/has_helpers/types/application_order_type.rb +18 -0
  93. data/app/graphql/has_helpers/types/cards/available_card_type.rb +20 -0
  94. data/app/graphql/has_helpers/types/cards/card_badge_type.rb +12 -0
  95. data/app/graphql/has_helpers/types/cards/card_config_type.rb +18 -0
  96. data/app/graphql/has_helpers/types/cards/card_data_type.rb +13 -0
  97. data/app/graphql/has_helpers/types/cards/card_entry_field_type.rb +21 -0
  98. data/app/graphql/has_helpers/types/cards/card_entry_type.rb +12 -0
  99. data/app/graphql/has_helpers/types/cards/card_field_config_type.rb +17 -0
  100. data/app/graphql/has_helpers/types/layouts/app_nav/link_section_type.rb +17 -0
  101. data/app/graphql/has_helpers/types/layouts/app_nav/link_type.rb +20 -0
  102. data/app/graphql/has_helpers/types/layouts/app_nav/sub_link_type.rb +17 -0
  103. data/app/graphql/has_helpers/types/layouts/app_nav/type.rb +16 -0
  104. data/app/graphql/has_helpers/types/lookup.rb +16 -0
  105. data/app/graphql/has_helpers/types/resource_tab/type.rb +15 -0
  106. data/app/graphql/has_helpers/types/role_type.rb +13 -0
  107. data/app/graphql/has_helpers/types/search/detail_badge_type.rb +15 -0
  108. data/app/graphql/has_helpers/types/search/detail_item_type.rb +14 -0
  109. data/app/graphql/has_helpers/types/search/detail_type.rb +16 -0
  110. data/app/graphql/has_helpers/types/search/filter_operation_enum.rb +19 -0
  111. data/app/graphql/has_helpers/types/search/input_type.rb +16 -0
  112. data/app/graphql/has_helpers/types/search/result_type.rb +72 -0
  113. data/app/graphql/has_helpers/types/search/search_filter_input_type.rb +17 -0
  114. data/app/graphql/has_helpers/types/search/type.rb +17 -0
  115. data/app/importers/has_helpers/cards/importer.rb +1223 -0
  116. data/app/lib/has_helpers/application_helper.rb +21 -0
  117. data/app/lib/has_helpers/dn/processor.rb +55 -0
  118. data/app/lib/has_helpers/dn/refresh.rb +13 -0
  119. data/app/lib/has_helpers/dn/utils/backfill_utils.rb +80 -0
  120. data/app/lib/has_helpers/dn/utils/query_utils.rb +216 -0
  121. data/app/lib/has_helpers/feature.rb +88 -0
  122. data/app/lib/has_helpers/hq_exception.rb +18 -0
  123. data/app/lib/has_helpers/index.rb +890 -0
  124. data/app/lib/has_helpers/organization_merge.rb +128 -0
  125. data/app/lib/has_helpers/query/elasticsearch.rb +20 -0
  126. data/app/lib/has_helpers/query/provider.rb +105 -0
  127. data/app/lib/has_helpers/query/sql.rb +133 -0
  128. data/app/lib/has_helpers/query.rb +14 -0
  129. data/app/lib/has_helpers/search/elasticsearch.rb +41 -0
  130. data/app/lib/has_helpers/search/elasticsearch_shared.rb +70 -0
  131. data/app/lib/has_helpers/search/provider.rb +149 -0
  132. data/app/lib/has_helpers/search/search_utils.rb +74 -0
  133. data/app/lib/has_helpers/search/sql_search.rb +219 -0
  134. data/app/lib/has_helpers/search.rb +46 -0
  135. data/app/models/ability.rb +233 -0
  136. data/app/models/has_helpers/application.rb +47 -0
  137. data/app/models/has_helpers/application_record.rb +7 -0
  138. data/app/models/has_helpers/cards/card_builder/base.rb +74 -0
  139. data/app/models/has_helpers/cards/card_builder/card_definition_builder.rb +486 -0
  140. data/app/models/has_helpers/cards/card_builder/definition_context.rb +82 -0
  141. data/app/models/has_helpers/cards/card_builder/field_builder.rb +142 -0
  142. data/app/models/has_helpers/cards/card_builder/resource_builder.rb +34 -0
  143. data/app/models/has_helpers/cards/card_definition.rb +41 -0
  144. data/app/models/has_helpers/cards/card_definition_resource.rb +19 -0
  145. data/app/models/has_helpers/cards/card_field.rb +39 -0
  146. data/app/models/has_helpers/cards/registry.rb +115 -0
  147. data/app/models/has_helpers/cards/role_card_field.rb +28 -0
  148. data/app/models/has_helpers/cards/role_resource_card.rb +41 -0
  149. data/app/models/has_helpers/dn_utils.rb +61 -0
  150. data/app/models/has_helpers/favorite.rb +20 -0
  151. data/app/models/has_helpers/master_record.rb +18 -0
  152. data/app/models/has_helpers/notification_alert.rb +52 -0
  153. data/app/models/has_helpers/organization.rb +16 -0
  154. data/app/models/has_helpers/organization_link.rb +92 -0
  155. data/app/models/has_helpers/organization_methods.rb +62 -0
  156. data/app/models/has_helpers/organization_option.rb +31 -0
  157. data/app/models/has_helpers/organization_resource.rb +45 -0
  158. data/app/models/has_helpers/pending_db_operation.rb +31 -0
  159. data/app/models/has_helpers/recently_viewed.rb +34 -0
  160. data/app/models/has_helpers/reindex_queue.rb +43 -0
  161. data/app/models/has_helpers/resource.rb +38 -0
  162. data/app/models/has_helpers/resource_group.rb +15 -0
  163. data/app/models/has_helpers/restriction.rb +15 -0
  164. data/app/models/has_helpers/restriction_operation.rb +13 -0
  165. data/app/models/has_helpers/role.rb +20 -0
  166. data/app/models/has_helpers/service_trust/audit_log.rb +20 -0
  167. data/app/models/has_helpers/service_trust/key.rb +56 -0
  168. data/app/models/has_helpers/stat.rb +13 -0
  169. data/app/models/has_helpers/user.rb +18 -0
  170. data/app/models/has_helpers/user_methods.rb +184 -0
  171. data/app/models/has_helpers/user_organization.rb +33 -0
  172. data/app/models/has_helpers/user_role.rb +27 -0
  173. data/app/models/has_helpers/user_session.rb +19 -0
  174. data/app/presenters/has_helpers/barcode_base_presenter.rb +113 -0
  175. data/app/presenters/has_helpers/base_presenter.rb +100 -0
  176. data/app/presenters/has_helpers/cacheable_item.rb +28 -0
  177. data/app/presenters/has_helpers/item_presenter.rb +52 -0
  178. data/app/presenters/has_helpers/items_presenter.rb +33 -0
  179. data/app/presenters/has_helpers/resource/action_presenter.rb +8 -0
  180. data/app/presenters/has_helpers/resource/cell_presenter.rb +52 -0
  181. data/app/presenters/has_helpers/resource/email_presenter.rb +34 -0
  182. data/app/presenters/has_helpers/resource/form_presenter.rb +76 -0
  183. data/app/presenters/has_helpers/resource/info_collection_presenter.rb +33 -0
  184. data/app/presenters/has_helpers/resource/info_presenter.rb +34 -0
  185. data/app/presenters/has_helpers/resource/list_presenter.rb +120 -0
  186. data/app/presenters/has_helpers/resource/note_presenter.rb +14 -0
  187. data/app/presenters/has_helpers/resource/row_presenter.rb +25 -0
  188. data/app/presenters/has_helpers/resource/tag_presenter.rb +31 -0
  189. data/app/presenters/has_helpers/search_presenter.rb +230 -0
  190. data/app/triggers/has_helpers/erase_denormalized_belongs_to_column_trigger.rb +85 -0
  191. data/app/triggers/has_helpers/limit_favorites.rb +97 -0
  192. data/app/utils/has_helpers/redis_configurable.rb +79 -0
  193. data/app/utils/has_helpers/sync_utils.rb +234 -0
  194. data/app/views/has_helpers/actions/_action.html.erb +31 -0
  195. data/app/views/has_helpers/alerts/_alert.html.erb +3 -0
  196. data/app/views/has_helpers/barcodes.html.erb +36 -0
  197. data/app/views/has_helpers/containers/_container.html.erb +3 -0
  198. data/app/views/has_helpers/email_notifier/system.html.erb +8 -0
  199. data/app/views/has_helpers/email_notifier/system.text.erb +7 -0
  200. data/app/views/has_helpers/enumerables/_enumerable.html.erb +1 -0
  201. data/app/views/has_helpers/icons/_icon.html.erb +1 -0
  202. data/app/views/has_helpers/render_objects/_render_object.html.erb +1 -0
  203. data/app/views/has_helpers/services/_service.html.erb +1 -0
  204. data/app/views/has_helpers/text_nodes/_text_node.html.erb +4 -0
  205. data/app/views/has_helpers/ui_attributes/_html_attrs.html.erb +1 -0
  206. data/app/workers/elasticsearch_process_queue.rb +11 -0
  207. data/app/workers/elasticsearch_reindex.rb +11 -0
  208. data/app/workers/elasticsearch_reindex_scheduler.rb +35 -0
  209. data/app/workers/good_job/configurable_backfill.rb +64 -0
  210. data/app/workers/good_job/cron_denormalization_stats_manager.rb +39 -0
  211. data/app/workers/good_job/denormalization_stats_worker.rb +57 -0
  212. data/app/workers/good_job/dn_update_worker.rb +30 -0
  213. data/app/workers/good_job/dn_worker.rb +47 -0
  214. data/app/workers/good_job/elasticsearch_old_index_cleaner_worker.rb +113 -0
  215. data/app/workers/good_job/elasticsearch_on_finish_reindex.rb +26 -0
  216. data/app/workers/good_job/elasticsearch_process_batch.rb +78 -0
  217. data/app/workers/good_job/elasticsearch_process_change_logs_master_worker.rb +27 -0
  218. data/app/workers/good_job/elasticsearch_process_change_logs_worker.rb +155 -0
  219. data/app/workers/good_job/elasticsearch_process_queue.rb +50 -0
  220. data/app/workers/good_job/elasticsearch_reindex.rb +31 -0
  221. data/app/workers/has_helpers/cards/orphan_card_sweeper.rb +28 -0
  222. data/app/workers/has_helpers/db_operations/clean_stats_worker.rb +42 -0
  223. data/app/workers/has_helpers/db_operations/helper_worker.rb +131 -0
  224. data/app/workers/has_helpers/db_operations/main_worker.rb +164 -0
  225. data/app/workers/has_helpers/db_operations/operations.rb +134 -0
  226. data/app/workers/has_helpers/db_operations/update_operations_stats_resume_worker.rb +35 -0
  227. data/app/workers/has_helpers/default_worker.rb +17 -0
  228. data/app/workers/has_helpers/good_job/notification_alert_cleanup_worker.rb +43 -0
  229. data/app/workers/has_helpers/service_trust/audit_log_cleanup_worker.rb +19 -0
  230. data/app/workers/sidekiq/elasticsearch_old_index_cleaner_worker.rb +112 -0
  231. data/app/workers/sidekiq/elasticsearch_process_batch.rb +87 -0
  232. data/app/workers/sidekiq/elasticsearch_process_queue.rb +40 -0
  233. data/app/workers/sidekiq/elasticsearch_reindex.rb +53 -0
  234. data/config/initializers/action_view.rb +7 -0
  235. data/config/initializers/inflections.rb +24 -0
  236. data/config/initializers/marginalia.rb +8 -0
  237. data/config/initializers/mime_types.rb +6 -0
  238. data/config/initializers/opentelemetry.rb +12 -0
  239. data/config/initializers/redis_conf.rb +40 -0
  240. data/config/initializers/searchkick.rb +9 -0
  241. data/config/initializers/will_paginate.rb +39 -0
  242. data/config/redis.yml +12 -0
  243. data/config/routes.rb +27 -0
  244. data/config/service_trust_routes.rb +5 -0
  245. data/config.ru +9 -0
  246. data/db/migrate/20230127194725_create_organization_table.rb +25 -0
  247. data/db/migrate/20230127194726_validate_organization_foreign_keys.rb +7 -0
  248. data/db/migrate/20230206141413_create_security_models.rb +42 -0
  249. data/db/migrate/20230206141513_create_restriction_model.rb +20 -0
  250. data/db/migrate/20230206142613_add_security_indexes.rb +14 -0
  251. data/db/migrate/20230206143513_security_model_constants_seed.rb +8 -0
  252. data/db/migrate/20230206161513_add_organization_to_security_models.rb +13 -0
  253. data/db/migrate/20230209121019_create_search_group_models.rb +36 -0
  254. data/db/migrate/20230209122919_add_search_group_indexes.rb +21 -0
  255. data/db/migrate/20230209181832_add_search_group_resources_type_constraint_trigger.rb +61 -0
  256. data/db/migrate/20230313220337_create_table_user_sessions.rb +31 -0
  257. data/db/migrate/20230517141106_update_resource_types.rb +12 -0
  258. data/db/migrate/20230518194611_add_resources_contraints.rb +17 -0
  259. data/db/migrate/20230518194642_create_nested_resource_model.rb +21 -0
  260. data/db/migrate/20230518194645_validate_security_models_constraints.rb +23 -0
  261. data/db/migrate/20230608125037_add_inactive_field_to_user_sessions.rb +7 -0
  262. data/db/migrate/20230919191525_add_parent_id_to_resources.rb +8 -0
  263. data/db/migrate/20230919191535_validate_parent_id_fk_resources.rb +7 -0
  264. data/db/migrate/20230919210456_drop_nested_resources.rb +7 -0
  265. data/db/migrate/20231222135620_add_user_role.rb +19 -0
  266. data/db/migrate/20240108172021_create_favorites_table.rb +20 -0
  267. data/db/migrate/20240108190209_create_organization_link_table_if_doesnt_exists.rb +31 -0
  268. data/db/migrate/20240109211445_validate_fks_org_links.rb +9 -0
  269. data/db/migrate/20240110135440_create_recently_vieweds.rb +20 -0
  270. data/db/migrate/20240112185312_link_type_options_seed.rb +7 -0
  271. data/db/migrate/20240116173201_organization_link_resource_tab_constraints.rb +19 -0
  272. data/db/migrate/20240131160949_add_user_organizations_table.rb +32 -0
  273. data/db/migrate/20240212132519_add_organization_in_user_sessions.rb +13 -0
  274. data/db/migrate/20240227135052_add_user_organization_composite_fks.rb +32 -0
  275. data/db/migrate/20240312193501_update_organization_links.rb +11 -0
  276. data/db/migrate/20240426185902_add_user_organizations_current_organization_column.rb +12 -0
  277. data/db/migrate/20240429214601_add_primary_trigger.rb +10 -0
  278. data/db/migrate/20241112131819_add_json_file_format_seed.rb +7 -0
  279. data/db/migrate/20250520133417_create_restriction_operations.rb +18 -0
  280. data/db/migrate/20250520133420_validate_create_restriction_operations.rb +8 -0
  281. data/db/migrate/20250520140642_add_indexes_to_restrictions.rb +9 -0
  282. data/db/migrate/20250529130741_create_notification_alerts_table.rb +28 -0
  283. data/db/migrate/20250530223332_create_data_migrations_table.rb +19 -0
  284. data/db/migrate/20250605121622_seed_notification_alert_status.rb +7 -0
  285. data/db/migrate/20250605131439_seed_notification_alert_types.rb +7 -0
  286. data/db/migrate/20250606173128_update_notification_alert_length_constraint.rb +18 -0
  287. data/db/migrate/20250606174043_validate_notification_alert_length_constraints.rb +8 -0
  288. data/db/migrate/20250624183000_add_data_import_alert_type.rb +11 -0
  289. data/db/migrate/20250722183935_create_organization_options_table.rb +38 -0
  290. data/db/migrate/20250722192724_validate_organization_options_fks_and_constraints.rb +32 -0
  291. data/db/migrate/20250722192936_add_indexes_to_organization_options_table.rb +15 -0
  292. data/db/migrate/20250915132448_add_column_restrictions_hash.rb +7 -0
  293. data/db/migrate/20250917143211_add_column_permissions_hash.rb +7 -0
  294. data/db/migrate/20251001145950_add_trust_this_device.rb +7 -0
  295. data/db/migrate/20251021130835_add_backend_urls_to_applications_table.rb +13 -0
  296. data/db/migrate/20251021172715_validate_backend_urls_constraints_in_applications.rb +9 -0
  297. data/db/migrate/20251030200020_create_card_definitions.rb +23 -0
  298. data/db/migrate/20251030201012_create_card_definition_resources.rb +24 -0
  299. data/db/migrate/20251030201236_create_card_fields.rb +34 -0
  300. data/db/migrate/20251103194317_create_role_resource_cards.rb +37 -0
  301. data/db/migrate/20251103194426_create_role_card_fields.rb +34 -0
  302. data/db/migrate/20251107173218_validate_columns_from_cards.rb +17 -0
  303. data/db/migrate/20251111173212_add_column_application_array.rb +7 -0
  304. data/db/migrate/20251112203326_add_card_types.rb +10 -0
  305. data/db/migrate/20251115120000_add_virtual_cards_support.rb +28 -0
  306. data/db/migrate/20251202231256_add_org_scoped_fk_role_resource_cards_to_roles.rb +14 -0
  307. data/db/migrate/20260105134504_add_accessor_field_resource_type.rb +7 -0
  308. data/db/migrate/20260115123000_add_default_visibility_to_card_definitions.rb +9 -0
  309. data/db/migrate/20260120175037_is_new_admin.rb +9 -0
  310. data/db/migrate/20260122392008_add_stats_table.rb +17 -0
  311. data/db/migrate/20260414204718_add_index_to_stats_table.rb +10 -0
  312. data/db/migrate/20260509120000_create_service_trust_keys.rb +25 -0
  313. data/db/migrate/20260509120001_create_service_trust_audit_logs.rb +26 -0
  314. data/db/migrate/20260511120000_add_direction_to_service_trust_audit_logs.rb +17 -0
  315. data/db/migrate/20260511121000_remove_role_fk_from_role_resource_cards.rb +19 -0
  316. data/db/migrate/20260511121001_add_disabled_at_to_role_resource_cards.rb +10 -0
  317. data/db/migrate/20260605120100_seed_hover_card_options.rb +8 -0
  318. data/db/migrate/20260608120000_seed_badge_list_card_data_type.rb +7 -0
  319. data/db/migrate/20260727000000_add_two_factor_trust_id_to_user_sessions.rb +11 -0
  320. data/db/seeds.rb +14 -0
  321. data/docs/Elasticsearch.md +23 -0
  322. data/docs/Search_API.md +126 -0
  323. data/docs/cards_role_proxy.md +107 -0
  324. data/docs/factory_api.md +135 -0
  325. data/has-helpers-pr-289-pipeline.yaml +16 -0
  326. data/has-helpers-pr-298-pipeline.yaml +15 -0
  327. data/has_helpers.gemspec +68 -0
  328. data/lib/active_record/migration/active_migration_patch.rb +123 -0
  329. data/lib/generators/has_helpers/install/USAGE +8 -0
  330. data/lib/generators/has_helpers/install/install_generator.rb +22 -0
  331. data/lib/generators/has_helpers/install/templates/migrate/has_helpers_initial_setup.rb +26 -0
  332. data/lib/has_helpers/active_record/base.rb +50 -0
  333. data/lib/has_helpers/active_record/date_range.rb +228 -0
  334. data/lib/has_helpers/active_record/nested_resource.rb +58 -0
  335. data/lib/has_helpers/active_record/validation.rb +63 -0
  336. data/lib/has_helpers/active_record.rb +520 -0
  337. data/lib/has_helpers/app/command.rb +107 -0
  338. data/lib/has_helpers/app.rb +10 -0
  339. data/lib/has_helpers/assets_precompile_helper.rb +20 -0
  340. data/lib/has_helpers/attributes.rb +196 -0
  341. data/lib/has_helpers/aws.rb +67 -0
  342. data/lib/has_helpers/cards/cache.rb +49 -0
  343. data/lib/has_helpers/cards/config.rb +42 -0
  344. data/lib/has_helpers/cards/remote_role.rb +27 -0
  345. data/lib/has_helpers/cards/remote_roles.rb +75 -0
  346. data/lib/has_helpers/cards/roles.rb +55 -0
  347. data/lib/has_helpers/cards.rb +34 -0
  348. data/lib/has_helpers/concerns/hydrate_concern.rb +76 -0
  349. data/lib/has_helpers/concerns/importable_accessors.rb +25 -0
  350. data/lib/has_helpers/concerns/restrictions_parseable.rb +51 -0
  351. data/lib/has_helpers/config.rb +11 -0
  352. data/lib/has_helpers/constant.rb +578 -0
  353. data/lib/has_helpers/constraints.rb +10 -0
  354. data/lib/has_helpers/core_ext/array.rb +28 -0
  355. data/lib/has_helpers/core_ext/date/infinity.rb +25 -0
  356. data/lib/has_helpers/core_ext/date.rb +39 -0
  357. data/lib/has_helpers/core_ext/enumerable.rb +20 -0
  358. data/lib/has_helpers/core_ext/false_class.rb +14 -0
  359. data/lib/has_helpers/core_ext/float.rb +18 -0
  360. data/lib/has_helpers/core_ext/hash.rb +71 -0
  361. data/lib/has_helpers/core_ext/integer.rb +18 -0
  362. data/lib/has_helpers/core_ext/nil_class.rb +30 -0
  363. data/lib/has_helpers/core_ext/object.rb +60 -0
  364. data/lib/has_helpers/core_ext/proc.rb +16 -0
  365. data/lib/has_helpers/core_ext/string.rb +81 -0
  366. data/lib/has_helpers/core_ext/symbol.rb +17 -0
  367. data/lib/has_helpers/core_ext/true_class.rb +14 -0
  368. data/lib/has_helpers/cursor.rb +46 -0
  369. data/lib/has_helpers/data_migration/base.rb +293 -0
  370. data/lib/has_helpers/data_migration/large_worker.rb +20 -0
  371. data/lib/has_helpers/data_migration/master_worker.rb +33 -0
  372. data/lib/has_helpers/data_migration/migrator.rb +83 -0
  373. data/lib/has_helpers/data_migration/model.rb +18 -0
  374. data/lib/has_helpers/data_migration/small_worker.rb +20 -0
  375. data/lib/has_helpers/data_migration.rb +8 -0
  376. data/lib/has_helpers/engine.rb +47 -0
  377. data/lib/has_helpers/extensions.rb +17 -0
  378. data/lib/has_helpers/factory_api.rb +47 -0
  379. data/lib/has_helpers/factory_scenario/definition.rb +33 -0
  380. data/lib/has_helpers/factory_scenario/dsl.rb +80 -0
  381. data/lib/has_helpers/factory_scenario/factory_bot_override.rb +53 -0
  382. data/lib/has_helpers/factory_scenario/registry.rb +31 -0
  383. data/lib/has_helpers/factory_scenario/runner.rb +285 -0
  384. data/lib/has_helpers/factory_scenario.rb +27 -0
  385. data/lib/has_helpers/fixed_expiration_time_cache_session_store.rb +20 -0
  386. data/lib/has_helpers/flattener/association.rb +140 -0
  387. data/lib/has_helpers/flattener/attribute.rb +42 -0
  388. data/lib/has_helpers/flattener/base.rb +428 -0
  389. data/lib/has_helpers/flattener/column/types.rb +71 -0
  390. data/lib/has_helpers/flattener/column.rb +97 -0
  391. data/lib/has_helpers/flattener/pivot.rb +49 -0
  392. data/lib/has_helpers/flattener/reset.rb +33 -0
  393. data/lib/has_helpers/flattener/resource.rb +114 -0
  394. data/lib/has_helpers/flattener/resource_generator.rb +21 -0
  395. data/lib/has_helpers/flattener/utils.rb +14 -0
  396. data/lib/has_helpers/flattener.rb +53 -0
  397. data/lib/has_helpers/hash_accessors.rb +62 -0
  398. data/lib/has_helpers/helpers/application.rb +291 -0
  399. data/lib/has_helpers/index/config.rb +15 -0
  400. data/lib/has_helpers/lazy_config.rb +61 -0
  401. data/lib/has_helpers/resource_importer.rb +260 -0
  402. data/lib/has_helpers/resources.rb +127 -0
  403. data/lib/has_helpers/rspec/constants.rb +61 -0
  404. data/lib/has_helpers/rspec/factories.rb +11 -0
  405. data/lib/has_helpers/rspec.rb +22 -0
  406. data/lib/has_helpers/sentry/graphql_trace.rb +37 -0
  407. data/lib/has_helpers/serializer.rb +41 -0
  408. data/lib/has_helpers/service_trust/audit.rb +45 -0
  409. data/lib/has_helpers/service_trust/authorization.rb +34 -0
  410. data/lib/has_helpers/service_trust/bearer_token.rb +23 -0
  411. data/lib/has_helpers/service_trust/capability.rb +32 -0
  412. data/lib/has_helpers/service_trust/client/response.rb +13 -0
  413. data/lib/has_helpers/service_trust/client/retry.rb +35 -0
  414. data/lib/has_helpers/service_trust/client.rb +128 -0
  415. data/lib/has_helpers/service_trust/configuration.rb +76 -0
  416. data/lib/has_helpers/service_trust/engine.rb +10 -0
  417. data/lib/has_helpers/service_trust/errors.rb +32 -0
  418. data/lib/has_helpers/service_trust/graphql/authorizable.rb +72 -0
  419. data/lib/has_helpers/service_trust/graphql_client.rb +54 -0
  420. data/lib/has_helpers/service_trust/jwks_client.rb +133 -0
  421. data/lib/has_helpers/service_trust/jwt_codec.rb +45 -0
  422. data/lib/has_helpers/service_trust/key_manager.rb +160 -0
  423. data/lib/has_helpers/service_trust/rate_limiter.rb +27 -0
  424. data/lib/has_helpers/service_trust/replay_cache.rb +26 -0
  425. data/lib/has_helpers/service_trust/signer.rb +47 -0
  426. data/lib/has_helpers/service_trust/test.rb +60 -0
  427. data/lib/has_helpers/service_trust/verifier.rb +85 -0
  428. data/lib/has_helpers/service_trust/verify_middleware.rb +55 -0
  429. data/lib/has_helpers/service_trust.rb +51 -0
  430. data/lib/has_helpers/test_helpers/factory_data/unit_addresses.rb +42 -0
  431. data/lib/has_helpers/test_helpers/factory_data/unit_advisors.rb +272 -0
  432. data/lib/has_helpers/test_helpers/factory_data/unit_emails.rb +37 -0
  433. data/lib/has_helpers/test_helpers/factory_data/unit_organizations.rb +48 -0
  434. data/lib/has_helpers/test_helpers/factory_data/unit_people.rb +34 -0
  435. data/lib/has_helpers/test_helpers/factory_data/unit_phones.rb +41 -0
  436. data/lib/has_helpers/test_helpers/factory_data/unit_states.rb +26 -0
  437. data/lib/has_helpers/test_helpers/factory_data/unit_webs.rb +31 -0
  438. data/lib/has_helpers/test_helpers/shoulda_helpers.rb +249 -0
  439. data/lib/has_helpers/ui_attributes.rb +39 -0
  440. data/lib/has_helpers/utils/action.rb +87 -0
  441. data/lib/has_helpers/utils/active_record_utils.rb +40 -0
  442. data/lib/has_helpers/utils/alert.rb +42 -0
  443. data/lib/has_helpers/utils/container.rb +46 -0
  444. data/lib/has_helpers/utils/dataset.rb +34 -0
  445. data/lib/has_helpers/utils/email_notifier.rb +15 -0
  446. data/lib/has_helpers/utils/icon.rb +66 -0
  447. data/lib/has_helpers/utils/input.rb +45 -0
  448. data/lib/has_helpers/utils/log_notifier.rb +79 -0
  449. data/lib/has_helpers/utils/render_object.rb +32 -0
  450. data/lib/has_helpers/utils/s3_utils.rb +37 -0
  451. data/lib/has_helpers/utils/service.rb +87 -0
  452. data/lib/has_helpers/utils/slack_conf.rb +31 -0
  453. data/lib/has_helpers/utils/slack_notifier.rb +42 -0
  454. data/lib/has_helpers/utils/text_node.rb +34 -0
  455. data/lib/has_helpers/utils/user_restrictions.rb +266 -0
  456. data/lib/has_helpers/utils.rb +19 -0
  457. data/lib/has_helpers/version.rb +6 -0
  458. data/lib/has_helpers/web_socket_publisher.rb +20 -0
  459. data/lib/has_helpers/webhook.rb +17 -0
  460. data/lib/has_helpers.rb +63 -0
  461. data/lib/hq/resource.rb +55 -0
  462. data/lib/hq/structure/inserts.rb +176 -0
  463. data/lib/hq/structure.rb +115 -0
  464. data/lib/tasks/has_helpers/service_trust.rake +39 -0
  465. data/script/rails +10 -0
  466. data/sorbet/config +5 -0
  467. data/sorbet/rbi/gems/actionpack.rbi +1361 -0
  468. data/sorbet/rbi/gems/activemodel.rbi +755 -0
  469. data/sorbet/rbi/gems/activerecord.rbi +4713 -0
  470. data/sorbet/rbi/gems/activesupport.rbi +1970 -0
  471. data/sorbet/rbi/gems/barby.rbi +129 -0
  472. data/sorbet/rbi/gems/better_errors.rbi +155 -0
  473. data/sorbet/rbi/gems/binding_of_caller.rbi +22 -0
  474. data/sorbet/rbi/gems/byebug.rbi +19 -0
  475. data/sorbet/rbi/gems/chronic.rbi +480 -0
  476. data/sorbet/rbi/gems/chunky_png.rbi +510 -0
  477. data/sorbet/rbi/gems/climate_control.rbi +45 -0
  478. data/sorbet/rbi/gems/coderay.rbi +91 -0
  479. data/sorbet/rbi/gems/concurrent-ruby.rbi +1587 -0
  480. data/sorbet/rbi/gems/debug_inspector.rbi +18 -0
  481. data/sorbet/rbi/gems/erubi.rbi +26 -0
  482. data/sorbet/rbi/gems/holidays.rbi +362 -0
  483. data/sorbet/rbi/gems/i18n.rbi +132 -0
  484. data/sorbet/rbi/gems/method_source.rbi +63 -0
  485. data/sorbet/rbi/gems/mime-types-data.rbi +16 -0
  486. data/sorbet/rbi/gems/mime-types.rbi +217 -0
  487. data/sorbet/rbi/gems/mimemagic.rbi +36 -0
  488. data/sorbet/rbi/gems/minitest.rbi +282 -0
  489. data/sorbet/rbi/gems/mustache.rbi +151 -0
  490. data/sorbet/rbi/gems/paperclip.rbi +644 -0
  491. data/sorbet/rbi/gems/parallel.rbi +81 -0
  492. data/sorbet/rbi/gems/parallel_tests.rbi +27 -0
  493. data/sorbet/rbi/gems/pry-rails.rbi +71 -0
  494. data/sorbet/rbi/gems/pry.rbi +1964 -0
  495. data/sorbet/rbi/gems/rack.rbi +228 -0
  496. data/sorbet/rbi/gems/railties.rbi +364 -0
  497. data/sorbet/rbi/gems/rspec-core.rbi +1704 -0
  498. data/sorbet/rbi/gems/rspec-expectations.rbi +389 -0
  499. data/sorbet/rbi/gems/rspec-support.rbi +206 -0
  500. data/sorbet/rbi/gems/rspec.rbi +14 -0
  501. data/sorbet/rbi/gems/spreadsheet_architect.rbi +10 -0
  502. data/sorbet/rbi/gems/sprockets.rbi +659 -0
  503. data/sorbet/rbi/gems/terrapin.rbi +115 -0
  504. data/sorbet/rbi/gems/testhq.rbi +14 -0
  505. data/sorbet/rbi/gems/thor.rbi +482 -0
  506. data/sorbet/rbi/gems/thread_safe.rbi +81 -0
  507. data/sorbet/rbi/gems/tzinfo.rbi +407 -0
  508. data/sorbet/rbi/gems/zeitwerk.rbi +131 -0
  509. data/sorbet/rbi/hidden-definitions/errors.txt +35111 -0
  510. data/sorbet/rbi/hidden-definitions/hidden.rbi +59974 -0
  511. data/sorbet/rbi/sorbet-typed/lib/actionmailer/all/actionmailer.rbi +13 -0
  512. data/sorbet/rbi/sorbet-typed/lib/actionpack/all/actionpack.rbi +855 -0
  513. data/sorbet/rbi/sorbet-typed/lib/actionview/all/actionview.rbi +314 -0
  514. data/sorbet/rbi/sorbet-typed/lib/activemodel/all/activemodel.rbi +423 -0
  515. data/sorbet/rbi/sorbet-typed/lib/activerecord/>=5.2/activerecord.rbi +17 -0
  516. data/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1415 -0
  517. data/sorbet/rbi/sorbet-typed/lib/activerecord/~>6.0.0/activerecord.rbi +475 -0
  518. data/sorbet/rbi/sorbet-typed/lib/activestorage/>=6.0.0/activestorage.rbi +19 -0
  519. data/sorbet/rbi/sorbet-typed/lib/activestorage/all/activestorage.rbi +173 -0
  520. data/sorbet/rbi/sorbet-typed/lib/activesupport/>=6.0.0.rc1/activesupport.rbi +23 -0
  521. data/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +625 -0
  522. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
  523. data/sorbet/rbi/sorbet-typed/lib/minitest/all/minitest.rbi +99 -0
  524. data/sorbet/rbi/sorbet-typed/lib/railties/all/railties.rbi +25 -0
  525. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +254 -0
  526. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
  527. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
  528. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
  529. data/sorbet/rbi/todo.rbi +244 -0
  530. data/spec/commands/cards/available_cards_command_spec.rb +90 -0
  531. data/spec/commands/cards/card_data_command_spec.rb +1048 -0
  532. data/spec/constructors/has_helpers/base_constructor_spec.rb +49 -0
  533. data/spec/controllers/has_helpers/controller_spec.rb +71 -0
  534. data/spec/controllers/has_helpers/xlsx_export_spec.rb +96 -0
  535. data/spec/factories/advisors.rb +20 -0
  536. data/spec/factories/anonymous_cowards.rb +5 -0
  537. data/spec/factories/applications.rb +5 -0
  538. data/spec/factories/appointments.rb +6 -0
  539. data/spec/factories/attachment.rb +15 -0
  540. data/spec/factories/audits.rb +5 -0
  541. data/spec/factories/basic_schedules.rb +12 -0
  542. data/spec/factories/cards/card_definition_resources.rb +7 -0
  543. data/spec/factories/cards/card_definitions.rb +11 -0
  544. data/spec/factories/cards/card_fields.rb +22 -0
  545. data/spec/factories/cards/role_card_fields.rb +17 -0
  546. data/spec/factories/cards/role_resource_cards.rb +12 -0
  547. data/spec/factories/constant_definition.rb +7 -0
  548. data/spec/factories/contracts.rb +10 -0
  549. data/spec/factories/data_migration_models.rb +9 -0
  550. data/spec/factories/demographics.rb +22 -0
  551. data/spec/factories/events.rb +21 -0
  552. data/spec/factories/firms.rb +21 -0
  553. data/spec/factories/imports.rb +9 -0
  554. data/spec/factories/meetups.rb +13 -0
  555. data/spec/factories/organizations.rb +13 -0
  556. data/spec/factories/policies.rb +7 -0
  557. data/spec/factories/policy_notes.rb +9 -0
  558. data/spec/factories/read_only_values.rb +7 -0
  559. data/spec/factories/resources.rb +7 -0
  560. data/spec/factories/roles.rb +11 -0
  561. data/spec/factories/schedules.rb +13 -0
  562. data/spec/factories/shared/flattener/attributes.rb +10 -0
  563. data/spec/factories/shared/flattener/columns.rb +6 -0
  564. data/spec/factories/shared/flattener/resources.rb +5 -0
  565. data/spec/factories/templates.rb +12 -0
  566. data/spec/factories/user_organizations.rb +23 -0
  567. data/spec/factories/user_session.rb +11 -0
  568. data/spec/factories/users.rb +55 -0
  569. data/spec/fixtures/sample_config.yml +3 -0
  570. data/spec/graphql/has_helpers/mutations/external_data_sync_spec.rb +101 -0
  571. data/spec/graphql/has_helpers/resolvers/cards/available_cards_spec.rb +36 -0
  572. data/spec/graphql/has_helpers/resolvers/cards/card_data_spec.rb +42 -0
  573. data/spec/graphql/has_helpers/resolvers/cards/hover_card_data_spec.rb +59 -0
  574. data/spec/has_helpers/cards/cache_spec.rb +58 -0
  575. data/spec/has_helpers/cards/config_spec.rb +68 -0
  576. data/spec/has_helpers/cards/orphan_card_sweeper_spec.rb +97 -0
  577. data/spec/has_helpers/cards/remote_role_spec.rb +17 -0
  578. data/spec/has_helpers/cards/remote_roles_spec.rb +97 -0
  579. data/spec/has_helpers/cards/roles_spec.rb +52 -0
  580. data/spec/has_helpers/cards/smoke_spec.rb +168 -0
  581. data/spec/has_helpers/cards/support.rb +52 -0
  582. data/spec/has_helpers/resolvers/internal/roles_spec.rb +73 -0
  583. data/spec/has_helpers/service_trust/audit_log_cleanup_worker_spec.rb +33 -0
  584. data/spec/has_helpers/service_trust/audit_spec.rb +70 -0
  585. data/spec/has_helpers/service_trust/authenticated_as_service_spec.rb +65 -0
  586. data/spec/has_helpers/service_trust/authorization_spec.rb +37 -0
  587. data/spec/has_helpers/service_trust/capability_spec.rb +35 -0
  588. data/spec/has_helpers/service_trust/client_spec.rb +129 -0
  589. data/spec/has_helpers/service_trust/configuration_spec.rb +35 -0
  590. data/spec/has_helpers/service_trust/engine_spec.rb +13 -0
  591. data/spec/has_helpers/service_trust/errors_spec.rb +23 -0
  592. data/spec/has_helpers/service_trust/graphql_authentication_spec.rb +59 -0
  593. data/spec/has_helpers/service_trust/graphql_authorizable_spec.rb +91 -0
  594. data/spec/has_helpers/service_trust/graphql_client_spec.rb +47 -0
  595. data/spec/has_helpers/service_trust/jwks_client_spec.rb +85 -0
  596. data/spec/has_helpers/service_trust/jwks_controller_spec.rb +47 -0
  597. data/spec/has_helpers/service_trust/jwt_codec_spec.rb +30 -0
  598. data/spec/has_helpers/service_trust/key_manager_spec.rb +80 -0
  599. data/spec/has_helpers/service_trust/key_spec.rb +52 -0
  600. data/spec/has_helpers/service_trust/rake_tasks_spec.rb +58 -0
  601. data/spec/has_helpers/service_trust/rate_limiter_spec.rb +31 -0
  602. data/spec/has_helpers/service_trust/replay_cache_spec.rb +29 -0
  603. data/spec/has_helpers/service_trust/signer_verifier_spec.rb +159 -0
  604. data/spec/has_helpers/service_trust/smoke_spec.rb +216 -0
  605. data/spec/has_helpers/service_trust/support.rb +121 -0
  606. data/spec/has_helpers/service_trust/test_module_spec.rb +39 -0
  607. data/spec/has_helpers/service_trust/verify_middleware_spec.rb +82 -0
  608. data/spec/helpers/application_spec.rb +155 -0
  609. data/spec/importers/cards/importer_spec.rb +861 -0
  610. data/spec/internal/app/assets/config/manifest.js +0 -0
  611. data/spec/internal/app/constants/cat_egory.rb +33 -0
  612. data/spec/internal/app/constants/color.rb +19 -0
  613. data/spec/internal/app/constants/exclude_group_nil_constant.rb +5 -0
  614. data/spec/internal/app/constants/foo.rb +6 -0
  615. data/spec/internal/app/constants/fruit.rb +3 -0
  616. data/spec/internal/app/constants/generic_group_example.rb +12 -0
  617. data/spec/internal/app/constants/my_constant.rb +4 -0
  618. data/spec/internal/app/constants/product.rb +3 -0
  619. data/spec/internal/app/constants/shirt_size.rb +18 -0
  620. data/spec/internal/app/constants/simple_option.rb +14 -0
  621. data/spec/internal/app/constants/status.rb +5 -0
  622. data/spec/internal/app/constructors/organization_constructor.rb +4 -0
  623. data/spec/internal/app/controllers/application_controller.rb +27 -0
  624. data/spec/internal/app/controllers/search_extensions.rb +3 -0
  625. data/spec/internal/app/indices/advisor_index.rb +35 -0
  626. data/spec/internal/app/indices/contract_index.rb +52 -0
  627. data/spec/internal/app/indices/firm_index.rb +16 -0
  628. data/spec/internal/app/indices/policy_index.rb +20 -0
  629. data/spec/internal/app/models/advisor.rb +24 -0
  630. data/spec/internal/app/models/agency.rb +3 -0
  631. data/spec/internal/app/models/anonymous_coward.rb +5 -0
  632. data/spec/internal/app/models/another_event.rb +2 -0
  633. data/spec/internal/app/models/appointment.rb +3 -0
  634. data/spec/internal/app/models/attachment.rb +10 -0
  635. data/spec/internal/app/models/basic_schedule.rb +6 -0
  636. data/spec/internal/app/models/beneficiary.rb +6 -0
  637. data/spec/internal/app/models/client.rb +5 -0
  638. data/spec/internal/app/models/contract.rb +9 -0
  639. data/spec/internal/app/models/demographic.rb +4 -0
  640. data/spec/internal/app/models/division.rb +3 -0
  641. data/spec/internal/app/models/event.rb +10 -0
  642. data/spec/internal/app/models/event_template.rb +1 -0
  643. data/spec/internal/app/models/firm.rb +18 -0
  644. data/spec/internal/app/models/has_audits/audit.rb +15 -0
  645. data/spec/internal/app/models/import.rb +7 -0
  646. data/spec/internal/app/models/meetup.rb +8 -0
  647. data/spec/internal/app/models/organization.rb +17 -0
  648. data/spec/internal/app/models/organization_event.rb +5 -0
  649. data/spec/internal/app/models/policy.rb +16 -0
  650. data/spec/internal/app/models/policy_holder.rb +7 -0
  651. data/spec/internal/app/models/policy_note.rb +8 -0
  652. data/spec/internal/app/models/project.rb +3 -0
  653. data/spec/internal/app/models/read_only_value.rb +8 -0
  654. data/spec/internal/app/models/schedule.rb +12 -0
  655. data/spec/internal/app/models/template.rb +9 -0
  656. data/spec/internal/app/models/user.rb +31 -0
  657. data/spec/internal/app/models/user_organization.rb +17 -0
  658. data/spec/internal/app/views/has_lists/lists/_table.html.erb +1 -0
  659. data/spec/internal/config/database-standard.yml +24 -0
  660. data/spec/internal/config/initializers/resources.rb +19 -0
  661. data/spec/internal/config/routes.rb +19 -0
  662. data/spec/internal/config/storage.yml +3 -0
  663. data/spec/internal/db/good_job_schema.rb +141 -0
  664. data/spec/internal/db/schema.rb +334 -0
  665. data/spec/internal/log/.gitignore +1 -0
  666. data/spec/internal/public/favicon.ico +0 -0
  667. data/spec/lib/flattener/base_spec.rb +93 -0
  668. data/spec/lib/flattener/column/types_spec.rb +65 -0
  669. data/spec/lib/has_helpers/active_record/base_spec.rb +53 -0
  670. data/spec/lib/has_helpers/active_record/date_range_spec.rb +498 -0
  671. data/spec/lib/has_helpers/active_record/lookup_model_spec.rb +408 -0
  672. data/spec/lib/has_helpers/active_record/nested_resource_spec.rb +43 -0
  673. data/spec/lib/has_helpers/app/command/reports/generator_specs.rb +887 -0
  674. data/spec/lib/has_helpers/app/command_spec.rb +117 -0
  675. data/spec/lib/has_helpers/app/support/mocks/graphql_reports_helpers.rb +96 -0
  676. data/spec/lib/has_helpers/app/support/mocks/reports_api_mock.rb +47 -0
  677. data/spec/lib/has_helpers/attributes_spec.rb +220 -0
  678. data/spec/lib/has_helpers/aws_spec.rb +126 -0
  679. data/spec/lib/has_helpers/concerns/hydrate_concern_spec.rb +473 -0
  680. data/spec/lib/has_helpers/constant/definition_spec.rb +128 -0
  681. data/spec/lib/has_helpers/constant_spec.rb +432 -0
  682. data/spec/lib/has_helpers/core_ext/array_spec.rb +22 -0
  683. data/spec/lib/has_helpers/core_ext/date/infinity_spec.rb +67 -0
  684. data/spec/lib/has_helpers/core_ext/date_spec.rb +27 -0
  685. data/spec/lib/has_helpers/core_ext/false_class_spec.rb +7 -0
  686. data/spec/lib/has_helpers/core_ext/float_spec.rb +9 -0
  687. data/spec/lib/has_helpers/core_ext/hash_spec.rb +48 -0
  688. data/spec/lib/has_helpers/core_ext/integer_spec.rb +9 -0
  689. data/spec/lib/has_helpers/core_ext/nil_class_spec.rb +17 -0
  690. data/spec/lib/has_helpers/core_ext/object_spec.rb +54 -0
  691. data/spec/lib/has_helpers/core_ext/proc_spec.rb +24 -0
  692. data/spec/lib/has_helpers/core_ext/string_spec.rb +154 -0
  693. data/spec/lib/has_helpers/core_ext/true_class_spec.rb +7 -0
  694. data/spec/lib/has_helpers/data_migration/base_spec.rb +470 -0
  695. data/spec/lib/has_helpers/data_migration/large_worker_spec.rb +34 -0
  696. data/spec/lib/has_helpers/data_migration/master_worker_spec.rb +51 -0
  697. data/spec/lib/has_helpers/data_migration/migrator_spec.rb +113 -0
  698. data/spec/lib/has_helpers/data_migration/model_spec.rb +52 -0
  699. data/spec/lib/has_helpers/data_migration/small_worker_spec.rb +34 -0
  700. data/spec/lib/has_helpers/good_job/notification_alert_cleanup_worker_spec.rb +89 -0
  701. data/spec/lib/has_helpers/hash_accessors_spec.rb +66 -0
  702. data/spec/lib/has_helpers/index_spec.rb +442 -0
  703. data/spec/lib/has_helpers/lazy_config_spec.rb +31 -0
  704. data/spec/lib/has_helpers/organization_merge_spec.rb +88 -0
  705. data/spec/lib/has_helpers/resource_importer_spec.rb +119 -0
  706. data/spec/lib/has_helpers/rspec_spec.rb +16 -0
  707. data/spec/lib/has_helpers/search/provider_spec.rb +26 -0
  708. data/spec/lib/has_helpers/search/search_utils_spec.rb +134 -0
  709. data/spec/lib/has_helpers/sentry/graphql_trace_spec.rb +140 -0
  710. data/spec/lib/has_helpers/ui_attributes_spec.rb +42 -0
  711. data/spec/lib/has_helpers/utils/action_spec.rb +49 -0
  712. data/spec/lib/has_helpers/utils/alert_spec.rb +33 -0
  713. data/spec/lib/has_helpers/utils/dataset_spec.rb +10 -0
  714. data/spec/lib/has_helpers/utils/icon_spec.rb +23 -0
  715. data/spec/lib/has_helpers/utils/input_spec.rb +40 -0
  716. data/spec/lib/has_helpers/utils/log_notifier_spec.rb +25 -0
  717. data/spec/lib/has_helpers/utils/render_object_spec.rb +17 -0
  718. data/spec/lib/has_helpers/utils/s3_utils_spec.rb +78 -0
  719. data/spec/lib/has_helpers/utils/service_spec.rb +79 -0
  720. data/spec/lib/has_helpers/utils/slack_notifier_spec.rb +70 -0
  721. data/spec/lib/has_helpers/utils/user_restrictions_spec.rb +343 -0
  722. data/spec/lib/hq/structure/inserts_spec.rb +152 -0
  723. data/spec/lib/hq/structure_spec.rb +12 -0
  724. data/spec/models/cards/base_spec.rb +149 -0
  725. data/spec/models/cards/card_definition_resource_spec.rb +103 -0
  726. data/spec/models/cards/card_definition_spec.rb +50 -0
  727. data/spec/models/cards/card_field_spec.rb +46 -0
  728. data/spec/models/cards/field_builder_spec.rb +318 -0
  729. data/spec/models/cards/registry_spec.rb +147 -0
  730. data/spec/models/cards/role_card_field_spec.rb +111 -0
  731. data/spec/models/cards/role_resource_card_spec.rb +112 -0
  732. data/spec/models/has_helpers/master_record_spec.rb +20 -0
  733. data/spec/models/has_helpers/user_organization_spec.rb +28 -0
  734. data/spec/models/has_helpers/user_session_spec.rb +16 -0
  735. data/spec/presenters/base_presenter_spec.rb +166 -0
  736. data/spec/rails_helper.rb +119 -0
  737. data/spec/requests/has_helpers/factory_controller_spec.rb +159 -0
  738. data/spec/requests/has_helpers/health_check_controller_spec.rb +37 -0
  739. data/spec/scenarios/empty_setup.rb +6 -0
  740. data/spec/spec_helper.rb +22 -0
  741. data/spec/support/has_helpers/database_helpers.rb +12 -0
  742. data/spec/utils/sync_utils_spec.rb +233 -0
  743. data/spec/workers/goodjob/elasticsearch_process_batch_spec.rb +94 -0
  744. data/spec/workers/goodjob/elasticsearch_process_change_logs_master_worker_spec.rb +40 -0
  745. data/spec/workers/goodjob/elasticsearch_process_change_logs_worker_spec.rb +82 -0
  746. data/spec/workers/goodjob/elasticsearch_process_queue_spec.rb +89 -0
  747. data/spec/workers/goodjob/elasticsearch_reindex_spec.rb +49 -0
  748. metadata +1593 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::EmailPresenter < ::HasHelpers::Resource::RowPresenter
4
+ attr_accessor :wrapped_object, :current_user
5
+
6
+ def title
7
+ wrapped_object.address
8
+ end
9
+
10
+ def subtitle
11
+ wrapped_object.location
12
+ end
13
+
14
+ def cells
15
+ ::HasHelpers::Resource::CellPresenter.wrap([
16
+ { value: wrapped_object.address,
17
+ service: service },
18
+ { value: wrapped_object.location,
19
+ is_header: true,
20
+ is_primary: wrapped_object.is_primary,
21
+ primary_title: wrapped_object["primary_title"] || "Preferred Email" }
22
+ ])
23
+ end
24
+
25
+ def service
26
+ "mailto:#{wrapped_object.address}"
27
+ end
28
+
29
+ delegate :is_primary, to: :wrapped_object
30
+
31
+ def primary_title
32
+ wrapped_object["primary_title"] || "Preferred Email"
33
+ end
34
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::FormPresenter < ::HasHelpers::BasePresenter
4
+ include ::HasForms::FormBuilder if defined?(::HasForms::FormBuilder)
5
+ attr_writer :current_user, :current_organization, :params
6
+
7
+ def express_form(*args)
8
+ if wrapped_object.express_step.nil? && wrapped_object.new_record?
9
+ wrapped_object.express_step = "basic_info"
10
+ elsif wrapped_object.express_step != "basic_info" && wrapped_object.new_record?
11
+ wrapped_object.express_step = "basic_info"
12
+ wrapped_object.errors.add(:express_step, "You must complete the first step to continue!")
13
+ end
14
+
15
+ options = args.extract_options!
16
+
17
+ resource = wrapped_object.class.name.demodulize.underscore
18
+ cancel_service =
19
+ if wrapped_object.new_record?
20
+ routes.send("new_#{ resource }_path")
21
+ else
22
+ routes.send("edit_#{ resource }_path", wrapped_object) << "/#{ wrapped_object.express_step }"
23
+ end
24
+
25
+ options.merge!(
26
+ legend: wrapped_object.express_step.titleize,
27
+ cancel_service: cancel_service,
28
+ submits: [
29
+ save_and_continue_options,
30
+ { name: "save_&_finish", value: "Save & Finish", skin: "btn btn-default" }
31
+ ]
32
+ )
33
+
34
+ form_builder(wrapped_object, options) do |form|
35
+ form.hidden_field :express_step, value: wrapped_object.express_step.html_safe # rubocop:disable Rails/OutputSafety
36
+
37
+ next_express_step = express_form_steps(form)
38
+
39
+ if next_express_step
40
+ form.hidden_field :next_express_step, prefix: "", value: next_express_step.html_safe # rubocop:disable Rails/OutputSafety
41
+ unless wrapped_object.new_record?
42
+ form.element.links << { caption: "Next Step", service: "#{form.element.service}/edit/#{ URI.parser.escape(next_express_step.to_s) }" }
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def params
49
+ @params || (controller && controller.params)
50
+ end
51
+
52
+ def current_user
53
+ @current_user || (controller && controller.current_user)
54
+ end
55
+
56
+ def current_organization
57
+ @current_organization || (controller && controller.current_organization)
58
+ end
59
+
60
+ def authorize_active_element_proc
61
+ @authorize_active_element_proc ||=
62
+ ->(fieldset) do
63
+ if fieldset.respond_to?(:legend) && fieldset.legend.present?
64
+ controller.current_ability.can?(:read, fieldset.legend)
65
+ else
66
+ true
67
+ end
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def save_and_continue_options
74
+ { name: "save_&_continue", value: "Save & Continue", skin: "btn btn-default form-submit-save", primary: true }
75
+ end
76
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class is used to present a collection of related entities. Be careful to use ::new instead of ::wrap to instantiate.
4
+ class HasHelpers::Resource::InfoCollectionPresenter < ::HasHelpers::BasePresenter
5
+ attr_writer :entities
6
+
7
+ # FIXME: It seems like there should be a better way to accomplish is_first, is_last without putting logic into the template (see _collection.html.erb)
8
+ def entities
9
+ entities = @entities
10
+
11
+ if entities.length == 1
12
+ entities.first.is_first = true
13
+ entities.first.is_last = true
14
+ elsif entities.length > 1
15
+ entities.first.is_first = true
16
+ entities.first.is_last = false
17
+
18
+ entities[1..-2] && entities[1..-2].each do |related_entity|
19
+ related_entity.is_first = false
20
+ related_entity.is_last = false
21
+ end
22
+
23
+ entities.last.is_first = false
24
+ entities.last.is_last = true
25
+ end
26
+
27
+ entities
28
+ end
29
+
30
+ def has_multiple?
31
+ @entities && @entities.length > 1
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class is used to present the informational details of a resource such as name, contact info, and provide service URLs for the resource.
4
+ class HasHelpers::Resource::InfoPresenter < ::HasHelpers::Resource::FormPresenter
5
+ attr_accessor :title, :current_user, :details_lists, :contact_info_caption, :is_primary, :is_warning, :is_first, :is_last
6
+ attr_writer :entity, :name, :service
7
+
8
+ def contact_info_service
9
+ service
10
+ end
11
+
12
+ def name
13
+ @name || (entity.respond_to?(:name) ? entity.name : nil)
14
+ end
15
+
16
+ # Returns a URL to the service associated with this entity
17
+ def service
18
+ @service ||=
19
+ if @service.nil?
20
+ "/#{entity.class.to_s.tableize}/#{entity.id}" if entity && entity.class.respond_to?(:table_name)
21
+ else
22
+ @service
23
+ end
24
+ end
25
+
26
+ def wrapped_object
27
+ @wrapped_object || @entity
28
+ end
29
+
30
+ # alias_method :entity, :wrapped_object
31
+ def entity
32
+ wrapped_object
33
+ end
34
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ # HasHelpers::Resource::ListPresenter is used to represent overview information for a resource record.
4
+ # The presenter is meant to display tabular data. Each list presenter has rows (RowPresenters) and each
5
+ # row has cells (CellPresenters).
6
+ class HasHelpers::Resource::ListPresenter < ::HasHelpers::BasePresenter
7
+ attr_writer :actions, :header_options, :icons,
8
+ :current_user # Used to pass through to presenters for content
9
+ attr_accessor :service, :caption, :caption_template, :caption_options, :subcaption, :headers, :is_sublist, :is_dropdown, :skin
10
+
11
+ # Content attributes: +rows+, +items+, +tags+
12
+ #
13
+ # These attributes provide different ways to specify the content of the current list presenter. Either +rows+ or +items+ can be used to
14
+ # specify tabular data (rows and cells). The difference between +rows+ and +items+ is that +rows+ must be instances of
15
+ # HasHelpers::Resource::RowPresenter. +items+ will be converted from Hash arguments into RowPresenter instances (if necessary).
16
+ #
17
+ # +tags+ can be used for a list which does not need tabular display but rather can be display in
18
+ # any manner, such as a horizontal list (wrapped).
19
+ #
20
+ # Use +rows+, +items+ and +tags+ _exclusively_
21
+ #
22
+ attr_writer :rows # +rows+ Represents the data for the current list and should be set to a either a collection of CellPresenters instances.
23
+ #
24
+ # E.g., :rows => [
25
+ # HasHelpers::Resource::RowPresenter.new(:items => [{:value => "Hello"}, {:value => "World"}]),
26
+ # HasHelpers::Resource::RowPresenter.new(:items => [{:value => "Adios"}])
27
+ # ]
28
+ # This manner of setting Row presenters explicitly offers the most flexibility and control.
29
+
30
+ attr_accessor :items # +items+ should be an array where each element represents a row and is either an Array of hash values (suitable to create
31
+ # Cell instances) or a Hash of options for a new RowPresenter. This is a shortcut alternative to setting the +rows+ attribute.
32
+ #
33
+ # Example, each element in +items+ represents a row, and each subelement beneath those represents the values for a cell.
34
+ # :items => [
35
+ # {:toggle => true, :items => [{:value => "Hello"}, {:value => "World"}]}, # Options for first row, two cells
36
+ # {:is_child => true, :toggle => true, :items => [{:value => "Adios"}]} # Options for second row, one cell
37
+ # ]
38
+ #
39
+ # Example, each element in +items+ represents a row, and each subelement beneath those represents the values for a cell.
40
+ # :items => [
41
+ # [{:value => "Hello"}, {:value => "World"}], # Items for first row, two cells
42
+ # [{:value => "Adios"}] # Items for second row, one cell
43
+ # ]
44
+ #
45
+ # ### NOTE: the above code is equivalent to
46
+ # # :items => [
47
+ # # {:items => [{:value => "Hello"}, {:value => "World"}]},
48
+ # # {:items => [{:value => "Adios"}]}
49
+ # # ]
50
+ #
51
+ # In some cases it may be desirable to leave a cell blank, in which case :blank => true should be used. There is also
52
+ # a :colspan option to have a cell across multiple columns. See HasHelpers::Resource::CellPresenter.
53
+
54
+ attr_writer :tags # +tags+ represents a list of non-tabular data and gets its name from its original use similar to a tag cloud.
55
+ # Tags are intended for horizontal lists which wrap to the container. Each tag displays a data point with an optional
56
+ # service link. +tags+ should be set to a collection for which each element is either value for a TagPresenter or
57
+ # a Hash of options for a tag presenter (which may be useful if options in addition to :value are needed).
58
+ #
59
+ # Example
60
+ # :tags => ["Lead", "Prospect"]
61
+ #
62
+ # Example - equivalent to the previous example
63
+ # :tags => [{:value => "Lead"}, {:value => "Prospect"}]
64
+ #
65
+ # Example - InfoPresenters may be passed as values for tags, see TagPresenter for details.
66
+ # writing_advisor_info_presenters = ::HasHelpers::Resource::InfoPresenter.wrap(client.advisors)
67
+ # :tags => writing_advisor_info_presenters
68
+
69
+ # Returns the assigned values of +@rows+ or items converted to rows.
70
+ def rows
71
+ @rows_memoized ||= @rows || items_to_rows # rubocop:disable Naming/MemoizedInstanceVariableName
72
+ end
73
+
74
+ # Returns presenter instances for all the options passed to :tags
75
+ def tags
76
+ @tags_memoized ||= (@tags || []).map do |tag_options| # rubocop:disable Naming/MemoizedInstanceVariableName
77
+ case tag_options
78
+ when ::HasHelpers::Resource::TagPresenter then tag_options
79
+ else ::HasHelpers::Resource::TagPresenter.new(tag_options)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Some lists may have data which should not be display in the initial (closed) state, but which should be
85
+ # accessible when a user toggles to an open state.
86
+ def has_rows_to_toggle
87
+ rows.present? && rows.any?(&:toggle)
88
+ end
89
+
90
+ def actions
91
+ (@actions || []).map do |action_or_attrs|
92
+ if action_or_attrs.is_a?(Hash)
93
+ ::HasHelpers::Resource::ActionPresenter.new(action_or_attrs)
94
+ else
95
+ action_or_attrs
96
+ end
97
+ end
98
+ end
99
+
100
+ def header_details_template
101
+ header_options[:template]
102
+ end
103
+
104
+ def header_options
105
+ @header_options || {}
106
+ end
107
+
108
+ def icons
109
+ @icons || []
110
+ end
111
+
112
+ private
113
+
114
+ def items_to_rows
115
+ @items && @items.map do |values|
116
+ options = values.is_a?(Array) ? { items: values } : values # Support two forms of options; either an Array of items to pass through to the row presenter as the value for the :items key, or a hash of values to use when instantiating the row presenter
117
+ ::HasHelpers::Resource::RowPresenter.new(options.reverse_merge(current_user: @current_user))
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers::Resource::NotePresenter
4
+ def note_items
5
+ @note_items ||= begin
6
+ if wrapped_object.respond_to?(:note)
7
+ note = wrapped_object.note
8
+ elsif wrapped_object.respond_to?(:demographic) && wrapped_object.demographic.respond_to?(:note)
9
+ note = wrapped_object.demographic.note
10
+ end
11
+ note.blank? ? [] : [[{ value: note }]]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::RowPresenter < ::HasHelpers::BasePresenter
4
+ attr_accessor :service, :is_child, :is_primary,
5
+ :toggle, # When set to true the visibility of the current row can be toggled on and off (off by default). This is used to initially hide contact info which is NOT primary.
6
+ :template, # When set the row will be rendered using the specified template rather than the default row template.
7
+ # For example the "tags" template can be specified when :value is set to a collection of TagPresenter
8
+ # objects, and there is a special template for policy advisors.
9
+ :is_section_header,
10
+ :items # +items+ should be an array of hash values suitable to create Cell instances.
11
+ # Set +items+ as an alternative to setting +cells+
12
+ attr_writer :cells,
13
+ :current_user # Used to pass through to presenters for content
14
+
15
+ # Returns the assigned value of +@cells+ or items converted to cells.
16
+ def cells
17
+ @cells ||= items_to_cells
18
+ end
19
+
20
+ private
21
+
22
+ def items_to_cells
23
+ @items && ::HasHelpers::Resource::CellPresenter.wrap_with_options(@items, current_user: @current_user)
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::TagPresenter < ::HasHelpers::BasePresenter
4
+ attr_writer :value # This will be displayed as the content of the tag. By default it will be rendered
5
+ # as a string, but other objects may be displayed by using a different template.
6
+ # In particular a value may be an instance of ::HasHelpers::Resource::infoPresenter.
7
+
8
+ attr_writer :template # When set, the tag presenter will be rendered with the given template. The only
9
+ # use I can think of right now is using a related_entity template (value must be
10
+ # set to an instance of Resource::InfoPresenter)
11
+
12
+ def template
13
+ @template || detect_template_from_value
14
+ end
15
+
16
+ def value
17
+ wrapped_object
18
+ end
19
+
20
+ private
21
+
22
+ def detect_template_from_value
23
+ case value
24
+ when ::HasHelpers::Resource::InfoPresenter then "info_tag"
25
+ end
26
+ end
27
+
28
+ def wrapped_object
29
+ @wrapped_object || @value
30
+ end
31
+ end
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::SearchPresenter < ::HasHelpers::BasePresenter
4
+ class DetailListPresenter < ::HasHelpers::BasePresenter
5
+ class DetailItemPresenter < ::HasHelpers::BasePresenter
6
+ attr_accessor :skin, :abbreviation
7
+ attr_writer :name, # String value to be displayed
8
+ :value, # TODO: Refactor name to value *
9
+ :icons,
10
+ :format,
11
+ :meta # Holds metadata for the detail item.
12
+ alias_method :icon=, :icons=
13
+
14
+ # === Returns
15
+ # One of the following in the given order:
16
+ # - The string explicitly set using the :name option.
17
+ # - The value passed as the :value option.
18
+ # - The name attribute of the wrapped object, if the object is present and responds to name (i.e. ActiveRecord models).
19
+ # - The wrapped_object itself, which is useful for just passing a string instead of a Hash arguments.
20
+ def value
21
+ unformatted_value = @name || @value || (wrapped_object && wrapped_object.try(:name)) || wrapped_object
22
+
23
+ transformed_value =
24
+ case @format
25
+ when "date" then Chronic.parse(unformatted_value)
26
+ else
27
+ unformatted_value
28
+ end
29
+ @format ? ::HasHelpers::Helpers::Application.send("format_#{ @format }", transformed_value) : transformed_value
30
+ end
31
+
32
+ def icons
33
+ [*(@icons || @icon)].lazy.map(&:to_icon)
34
+ end
35
+
36
+ def meta
37
+ @meta ||= {}
38
+ end
39
+
40
+ def to_h
41
+ { name: value }
42
+ end
43
+ end
44
+
45
+ attr_accessor :skin
46
+
47
+ def details
48
+ (wrapped_object || []).lazy.select do |_heading, *items|
49
+ items.any?
50
+ end.map do |heading, *items|
51
+ detail_items = (
52
+ case items.first
53
+ when Hash then [items.first]
54
+ else
55
+ [*[*items].first] # [*[*items].first] handles *items catching either a single record instance or an array of hashes.
56
+ end
57
+ ).map do |detail_args|
58
+ unless detail_args.has_key?("format")
59
+ # Automatically select format
60
+ format = heading.to_s.singularize.underscore
61
+ if ::HasHelpers::Helpers::Application.respond_to?("format_#{ format }")
62
+ detail_args["format"] = format
63
+ end
64
+ end
65
+
66
+ DetailItemPresenter.new(detail_args)
67
+ end
68
+
69
+ [
70
+ heading,
71
+ detail_items,
72
+ detail_items.all? { |item| item.skin && item.skin.include?("sub-item") } ? "sub-item-group" : nil
73
+ ]
74
+ end
75
+ end
76
+
77
+ def to_h
78
+ details.map do |heading, detail_items, skin|
79
+ {
80
+ id: detail_items.hash,
81
+ heading: heading,
82
+ detail_items: detail_items,
83
+ skin: skin
84
+ }
85
+ end
86
+ end
87
+ end
88
+
89
+ class ResultPresenter < ::HasHelpers::BasePresenter
90
+ attr_accessor :name, :id, :klass, :is_heading, :search_submit,
91
+ :photo_info, :sub_item, :sub_item_type, :screen, :abbreviation, :show_type
92
+ attr_writer :details, :icon, :klass_name, :service, :type
93
+
94
+ def detail_list
95
+ details = @details || {}
96
+ detail_list_options = { wrapped_object: details }
97
+ detail_list_options[:skin] = "sub-item-only" if @details.blank? || (@details && @details.all? { |_k, v| v.blank? })
98
+ DetailListPresenter.new(detail_list_options)
99
+ end
100
+
101
+ def icon
102
+ !photo_service && @icon # && @icon.to_icon # only return icon name
103
+ end
104
+
105
+ def photo_service
106
+ if @photo_service_memoized
107
+ @photo_service
108
+ else
109
+ @photo_service_memoized = true
110
+ @photo_service ||= ::HasHelpers::Helpers::Application.photo_info_service(
111
+ @photo_info,
112
+ application: ->(resource_typish, *_) { %w[users organizations].include?(resource_typish) ? "hqadmin" : ::HasHelpers::Application.project }
113
+ )
114
+ end
115
+ end
116
+
117
+ def service
118
+ @service ||= "/#{ klass_name.demodulize.tableize }/#{ id }".to_service
119
+ @service.respond_to?(:call) ? @service.call : @service
120
+ end
121
+
122
+ def klass_name
123
+ @klass_name || klass.name
124
+ end
125
+
126
+ def base_type
127
+ @type&.safe_constantize&.base_class&.name
128
+ end
129
+
130
+ def type
131
+ return unless show_type && @type
132
+ @type.demodulize.titleize
133
+ end
134
+
135
+ def to_h
136
+ {
137
+ image_url: photo_service&.url,
138
+ icon: icon,
139
+ abbreviation: abbreviation,
140
+ label: name,
141
+ value: id,
142
+ sub_item: sub_item,
143
+ details: detail_list.to_h,
144
+ type: type,
145
+ baseType: base_type&.demodulize,
146
+ screen: screen,
147
+ showType: show_type
148
+ }
149
+ end
150
+ end
151
+
152
+ attr_writer :search_submit, :results_id_field
153
+ attr_accessor :screen, :multiscreen, :inline_add, :page, :per_page, :show_type, :exact_submit
154
+
155
+ # Returns an associative Array, where the keys are screen names and values are collections of results.
156
+ def results(
157
+ format_ungrouped: false # When set to true the results will NOT be grouped.
158
+ )
159
+ intermediate_results = raw_results || {}
160
+
161
+ intermediate_results = intermediate_results.map do |result|
162
+ case result
163
+ when ::ActiveRecord::Base
164
+ # `result` should be an owner detail object, e.g. an OwnerAdvisor rather than an Advisor.
165
+ ResultPresenter.new(
166
+ name: result.try(:name),
167
+ type: result.try(:type) || result.class.name,
168
+ klass: result.class,
169
+ service: -> { result.to_service }, # Service may not be needed, so delay its evaluation by wrapping it in a proc.
170
+ id: result.try(results_id_field),
171
+ details: result.try(:detail) || {},
172
+ sub_item: result.try(:sub_item),
173
+ sub_item_type: result.try(:sub_item_type),
174
+ photo_info: result.try(:photo_info),
175
+ icon: result.try(:icon) || :circle,
176
+ abbreviation: result.try(:abbreviation),
177
+ search_submit: search_submit.is_a?(Proc) ? search_submit.call(result) : search_submit,
178
+ screen: screen,
179
+ show_type: show_type
180
+ )
181
+ when ::Hash
182
+ ResultPresenter.new(result)
183
+ else # Handles String, which is displayed as a heading
184
+ ResultPresenter.new(name: result.to_s.titleize, is_heading: true)
185
+ end
186
+ end
187
+
188
+ if format_ungrouped
189
+ intermediate_results.map(&:to_h)
190
+ else
191
+ # Wrap the results in a hash if they are not already.
192
+ intermediate_results = { nil => intermediate_results } unless intermediate_results.respond_to?(:keys) || intermediate_results.try(:blank?)
193
+ intermediate_results
194
+ end
195
+ end
196
+
197
+ def raw_results
198
+ wrapped_object
199
+ end
200
+
201
+ def search_submit
202
+ @search_submit_memoized ||= if @multiscreen # rubocop:disable Naming/MemoizedInstanceVariableName
203
+ if @exact_submit
204
+ @exact_submit
205
+ elsif @search_submit.is_a?(Proc)
206
+ -> result { "#{ @search_submit[result] }[#{ @screen.singularize.foreign_key }]" }
207
+ else
208
+ "#{ @search_submit }[#{ @screen.singularize.foreign_key }]"
209
+ end
210
+ else
211
+ @search_submit
212
+ end
213
+ end
214
+
215
+ def icon
216
+ @icon && @icon.to_icon("icon-item")
217
+ end
218
+
219
+ def to_h
220
+ results.map do |group, results|
221
+ { name: group, results: results.map(&:to_h) }
222
+ end
223
+ end
224
+
225
+ private
226
+
227
+ def results_id_field ### We could also do the same thing with name, table_name, etc. if needed. ###
228
+ @results_id_field || :id
229
+ end
230
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers
4
+ class EraseDenormalizedBelongsToColumnTrigger < ::PsqlHq::Trigger
5
+ attr_reader :owner_table, :owner_column, :affected_table, :update_fields, :column_to_evaluate
6
+
7
+ # owner_table -> table where the trigger resides
8
+ # owner_column -> column where the trigger resides
9
+ # affected_table -> table where the update it is made
10
+ # update_fields -> columns to be changed in affected_table - can be an array or not
11
+ # column_to_evaluate -> condition that evaluates if the change has to be made or not (eg. writing advisor that belongs to an opportunity has to have opportunity_id not null)
12
+ def initialize(owner_table, owner_column, affected_table, update_fields, column_to_evaluate, **options)
13
+ @owner_table = owner_table
14
+ @owner_column = owner_column
15
+ @affected_table = affected_table
16
+ @update_fields = update_fields
17
+ @column_to_evaluate = column_to_evaluate
18
+ super(owner_table, update_fields, options)
19
+ end
20
+
21
+ def self.prefix
22
+ "HQD"
23
+ end
24
+
25
+ # if array then use this
26
+ def affected_fields
27
+ update_fields.kind_of?(Array) ? update_fields.join(" = NULL, ") : update_fields.to_s
28
+ end
29
+
30
+ def name
31
+ fields_name = update_fields.kind_of?(Array) ? update_fields.join("_") : update_fields.to_s
32
+ "#{fields_name}_on_#{affected_table}_#{owner_table.downcase}"
33
+ end
34
+
35
+ def drop
36
+ self.drop_by_function_name(function_name)
37
+ end
38
+
39
+ def create
40
+ ::ActiveRecord::Base.connection.execute sql_to_add_function
41
+ after_or_before = trigger_after? ? "AFTER" : "BEFORE"
42
+ ::ActiveRecord::Base.connection.execute <<-SQL
43
+ CREATE TRIGGER "#{trigger_name}"
44
+ #{after_or_before} DELETE
45
+ ON #{owner_table}
46
+ FOR EACH ROW
47
+ EXECUTE PROCEDURE "#{function_name}"();
48
+ SQL
49
+ puts "-- Created trigger #{trigger_name} and function #{function_name}."
50
+ end
51
+
52
+ private
53
+
54
+ def trigger_after?
55
+ false
56
+ end
57
+
58
+ def sql_to_add_function
59
+ <<-END_OF_SQL
60
+ CREATE OR REPLACE FUNCTION public."#{function_name}"()
61
+ RETURNS trigger
62
+ LANGUAGE 'plpgsql'
63
+ SECURITY DEFINER
64
+ AS $function$
65
+ BEGIN
66
+ UPDATE
67
+ #{affected_table}
68
+ SET
69
+ #{update_fields} = NULL
70
+ WHERE
71
+ #{column_to_evaluate} = OLD.#{owner_column};
72
+ RETURN OLD;
73
+ END
74
+ $function$;
75
+ END_OF_SQL
76
+ end
77
+
78
+ def drop_by_function_name(function_name)
79
+ ::ActiveRecord::Base.connection.execute <<-SQL
80
+ DROP FUNCTION IF EXISTS \"#{function_name}\"() CASCADE;
81
+ SQL
82
+ puts "-- Dropped #{function_name} (if it existed) and any dependent triggers"
83
+ end
84
+ end
85
+ end