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,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers::UserMethods
4
+ REMOTE_ATTRS = %w[first_name last_name photo_file_name photo_content_type photo_file_size photo_updated_at]
5
+
6
+ # Including apps' user models can use this to set common settings
7
+ # for user photos.
8
+ PHOTO_OPTIONS = {
9
+ # Always use the hqadmin bucket for user photos
10
+ bucket: "hqadmin-#{::HasUtils::Env.current_environment}", # TODO: upgrade paperclip to 6 and you can use -> { "#{::HasHelpers::Application::HQADMIN.name}-#{ ::HasUtils::Env.current_environment }" },
11
+ }.freeze
12
+
13
+ def self.included(base)
14
+ base.class_eval do
15
+ attr_accessor :skip_update_master_record # When set to a truthy value this prevents pushing changes to the AdminHQ API on save.
16
+ attr_accessor :master_record_attributes # Set with the attributes returned from pushing user changes to the AdminHQ API
17
+ attr_accessor :extra_attributes # Stores information retrieved from hqsso. These can be handled every time cas_extra_attributes=
18
+ # is called by creating a method called handle_extra_attributes on the class/module that includes this module.
19
+
20
+ def ip_whitelist
21
+ # The support user does not have an IP whitelist.
22
+ # Support users can log in from anywhere.
23
+ return nil if is_support?
24
+ [*super, *organization.ip_whitelist].presence
25
+ end
26
+
27
+ serialize :permissions_hash, type: Hash
28
+ serialize :applications_array, type: Array
29
+
30
+ # Runs within the save transaction. Pushes changes to IAMHQ
31
+ # Do not run this callback from within IAMHQ
32
+ after_save :update_master_record,
33
+ unless: -> { HasHelpers::Application.current_application == ::HasHelpers::Application::HQADMIN || skip_update_master_record }
34
+
35
+ after_commit :save_master_record_attributes, if: :master_record_attributes
36
+ end
37
+ base.send(:include, InstanceMethods)
38
+ end
39
+
40
+ module InstanceMethods
41
+ def cas_extra_attributes=(extra_attributes)
42
+ org_id = extra_attributes["organization_id_or_uuid"] || extra_attributes["organization_id"]
43
+ org = ::HasHelpers::Organization.find_or_initialize_by(id: org_id)
44
+ time_zone = ::TimeZone.find_by(name: extra_attributes["organization_time_zone_name"])
45
+ if time_zone.nil?
46
+ time_zone = org.time_zone
47
+ data = {
48
+ message: "TimeZone Lookup Failed",
49
+ organization: org.inspect,
50
+ user: self.inspect,
51
+ extra_attributes: extra_attributes,
52
+ }.inspect
53
+ HasHelpers::LogNotifier.notify(
54
+ HasHelpers::HQException.new(data, backtrace: caller)
55
+ )
56
+ end
57
+
58
+ organization_attributes = {
59
+ code_name: extra_attributes["organization_code_name"],
60
+ domain: extra_attributes["organization_domain"],
61
+ ip_whitelist: extra_attributes["organization_ip_whitelist"],
62
+ is_use_roles_for_authorization: extra_attributes["organization_is_use_roles_for_authorization"],
63
+ name: extra_attributes["organization_name"],
64
+ time_zone_id: time_zone.id,
65
+ }
66
+ organization_attributes[:is_active] = extra_attributes["organization_is_active"] if ::HasHelpers::Organization.column_names.include?("is_active")
67
+ organization_attributes[:start_date] = extra_attributes["organization_go_live_date"] if org.start_date.blank?
68
+
69
+ if !org.update(organization_attributes) && ::Rails.application.config.x.support_email_address.present?
70
+ notifier_body = {
71
+ "User" => username,
72
+ "Class" => self.class.name,
73
+ "Org ID" => org.id,
74
+ "Organization name" => org.name,
75
+ "Org name of extra attrs" => extra_attributes["organization_name"] || "no attr found",
76
+ "Test org name" => extra_attributes["organization_name_test"] || "no name found",
77
+ "Created at" => extra_attributes["created_at_test"],
78
+ "Errors" => org.errors.full_messages.join(", "),
79
+ "Backtrace" => Thread.current.backtrace.first(100),
80
+ }
81
+ ::HasHelpers::EmailNotifier.system(subject: "Error synchronizing organization attributes", to: "tools@onehq.com", body: notifier_body).deliver_now
82
+ end
83
+
84
+ # Ensure there's a join
85
+ link = user_organizations.find_or_initialize_by(organization_id: org.id)
86
+ link.is_primary = true
87
+
88
+ self.assign_attributes(
89
+ applications_array: extra_attributes["user_applications_array"],
90
+ import_key: extra_attributes["user_import_key"],
91
+ ip_whitelist: extra_attributes["user_ip_whitelist"],
92
+ is_support: extra_attributes["user_is_support"] ? true : nil, # bi-state bool here, regular bool in hqsso
93
+ permissions_hash: extra_attributes["user_permissions_hash"],
94
+ photo_content_type: extra_attributes["user_photo_content_type"],
95
+ photo_file_name: extra_attributes["user_photo_file_name"],
96
+ photo_file_size: extra_attributes["user_photo_file_size"],
97
+ photo_updated_at: extra_attributes["user_photo_updated_at"],
98
+ production_api_key: extra_attributes["user_production_api_key"],
99
+ staging_api_key: extra_attributes["user_staging_api_key"],
100
+ username: extra_attributes["user_username"],
101
+ )
102
+
103
+ self.first_name = extra_attributes["user_first_name"] if respond_to?(:first_name)
104
+ self.last_name = extra_attributes["user_last_name"] if respond_to?(:last_name)
105
+
106
+ # only for new users
107
+ if new_record?
108
+ self.id = extra_attributes["user_id"]
109
+ self.created_by = self
110
+ self.updated_by = self
111
+ end
112
+
113
+ # Do not push changes to HQAdmin since the latest changes are currently being applied.
114
+ # This is not strictly necessary, but it currenty prevents a pointless API call.
115
+ self.skip_update_master_record = true
116
+
117
+ self.extra_attributes = extra_attributes.select { |attr_name, _| attr_name.start_with?("user") }
118
+ org.extra_attributes = extra_attributes.select { |attr_name, _| attr_name.start_with?("organization") }
119
+ self.send(:handle_extra_attributes) if self.respond_to?(:handle_extra_attributes, true)
120
+ org.send(:handle_extra_attributes) if org.respond_to?(:handle_extra_attributes, true)
121
+ link.save!
122
+ # Make sure all other links are not primary
123
+ user_organizations.where.not(id: link.id).update_all(is_primary: nil)
124
+ end
125
+
126
+ def abbreviated_name
127
+ receiver = respond_to?(:demographic) ? demographic : self
128
+ "#{receiver.first_name}#{receiver.last_name.to_s.sub(/^(.).*/, ' \1.')}"
129
+ end
130
+
131
+ def is_admin?
132
+ applications_array.include?(::HasHelpers::Application::HQADMIN.name)
133
+ end
134
+
135
+ def is_super_user?
136
+ is_admin? || is_support?
137
+ end
138
+
139
+ protected
140
+
141
+ ###### normalizations ######
142
+
143
+ # Pushes changes to the master record (in HQAdmin) through an API.
144
+ # This should run within the save transaction so that a failed API request will
145
+ # prevent a local update.
146
+ def update_master_record
147
+ changed_attr_names = changed.select { |attr| REMOTE_ATTRS.include?(attr) } # Exclude some attributes from update
148
+ changed_attrs = attributes.slice(*changed_attr_names)
149
+
150
+ # Also grab changed attrs from the associated Demographic record (if applicable).
151
+ if respond_to?(:demographic) && demographic
152
+ # Need to access the previous_changes because the Demographic record (child) will be saved before the current user.
153
+ demographic.previous_changes.select { |attr, _values| REMOTE_ATTRS.include?(attr) }.each do |attr, (_, new_value)|
154
+ changed_attrs[attr] = new_value
155
+ end
156
+ end
157
+
158
+ if changed_attrs.any?
159
+ # TODO: 2015-04-01 Revert this code which disables SSL verification. This was only intended as a temporary measure to work around the issue described below. *
160
+ response = ::RestClient.post("#{::HasHelpers::Application::HQADMIN.url}/api/v1/users/#{id}", changed_attrs)
161
+ # response = ::RestClient::Resource.new("#{::HasHelpers::Application::HQADMIN.url}/api/v1/users/#{id}", verify_ssl: OpenSSL::SSL::VERIFY_NONE).post(changed_attrs) # Turn off SSL verification which has recently started causing connection issues here due to our invalid cert for HQAdmin (in production).
162
+
163
+ response_data = JSON.parse(response.body)
164
+
165
+ self.master_record_attributes = response_data["user"] # Hold onto the user attributes received in the API response.
166
+ response_data["message"] == "success" # Returning a falsey value here will cancel the save operation when the current method is used as an after save callback.
167
+ end
168
+ end
169
+
170
+ def save_master_record_attributes
171
+ self.skip_update_master_record = true
172
+ attrs = master_record_attributes # Grab another reference to the new user attributes, so the virtual attribute can be cleared.
173
+ self.master_record_attributes = nil # Clear this out so the callback does not loop.
174
+
175
+ if respond_to?(:demographic) && demographic
176
+ remote_demographic_attrs = REMOTE_ATTRS.select { |remote_attr| demographic.respond_to?("#{remote_attr}=") } # Get a list of all the remote attrs which match up with Demographic
177
+ demographic.assign_attributes attrs.slice(*remote_demographic_attrs) # Do not update here. Allow the Demographic to be saved as part of the save operation for the current user in order to have all updates within a single transaction.
178
+ end
179
+
180
+ remote_user_attrs = REMOTE_ATTRS.select { |remote_attr| respond_to?("#{remote_attr}=") } # Get a list of all the remote attrs which match up with User
181
+ update attrs.slice(*remote_user_attrs) # In addition to updating the current user, this will save the Demographic record if one exists and is modified.
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers
4
+ class UserOrganization < ApplicationRecord
5
+ self.table_name = :user_organizations
6
+
7
+ ###### callbacks ######
8
+
9
+ ###### variables ######
10
+
11
+ ###### associations ######
12
+ belongs_to :organization, class_name: "::HasHelpers::Organization", optional: false
13
+ belongs_to :user, class_name: "::HasHelpers::User", optional: false
14
+
15
+ ###### triggers ######
16
+ auto_primary foreign_keys: ["user_id"]
17
+ after_delete_primary foreign_keys: ["user_id"]
18
+
19
+ ###### externals ######
20
+
21
+ ###### validations ######
22
+ validates :user_id, uniqueness: {
23
+ scope: :organization_id,
24
+ message: "The user already has this organization set"
25
+ }
26
+
27
+ ###### scopes ######
28
+
29
+ ###### class methods ######
30
+
31
+ ###### instance methods ######
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers
4
+ class UserRole < ApplicationRecord
5
+ self.table_name = :user_roles
6
+
7
+ ###### callbacks ######
8
+ autoset :organization_id
9
+
10
+ ###### variables ######
11
+
12
+ ###### associations ######
13
+ belongs_to :role, optional: false
14
+ belongs_to :organization, class_name: "::HasHelpers::Organization"
15
+ belongs_to :user, class_name: "::HasHelpers::User", optional: false
16
+
17
+ ###### externals ######
18
+
19
+ ###### validations ######
20
+
21
+ ###### scopes ######
22
+
23
+ ###### class methods ######
24
+
25
+ ###### instance methods ######
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasHelpers
4
+ class UserSession < ApplicationRecord
5
+ self.table_name = :user_sessions
6
+
7
+ ###### associations ######
8
+ belongs_to :user
9
+
10
+ ###### validations ######
11
+ validates :user_id, presence: true
12
+ validates :session_id, presence: true, uniqueness: { scope: [:user_id] }
13
+ validates :expired_at, presence: true
14
+
15
+ ###### scopes ######
16
+ scope :expired, -> { where("expired_at < ?", Time.current) }
17
+ scope :active, -> { where("? BETWEEN created_at AND expired_at", Time.current) }
18
+ end
19
+ end
@@ -0,0 +1,113 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ # An "abstract" superclass for BarcodePresenter subclasses. Each subclass must
5
+ # overwrite the private #get_texts method to return the data that should be
6
+ # rendered as barcodes.
7
+ require "barby/barcode/code_128"
8
+ require "barby/outputter/png_outputter"
9
+ require "barby/outputter/html_outputter"
10
+
11
+ module HasHelpers
12
+ class BarcodeBasePresenter < ::HasHelpers::BasePresenter
13
+ ##### CLASS METHODS #####
14
+
15
+ # Returns a BarcodePresenter class that matches the object passed in. It
16
+ # does this by looking for a BarcodePresenter matching the object's base
17
+ # class. For example, if the object is a Policy (or any subclass of Policy),
18
+ # this method will see if there is a Policy::BarcodePresenter class. If it
19
+ # finds a matching class, it returns the class; if not, it returns nil.
20
+ def self.get_presenter_class(object)
21
+ base_class_name = object.class.base_class.name
22
+ "::#{base_class_name}::BarcodePresenter".safe_constantize
23
+ end
24
+
25
+ # Same as #get_presenter_class, but raises an error if it cannot find a
26
+ # matching BarcodePresenter class.
27
+ def self.get_presenter_class!(object)
28
+ presenter_class = get_presenter_class(object)
29
+ raise "Cannot find a barcode presenter for #{object.class}." unless presenter_class
30
+ presenter_class
31
+ end
32
+
33
+ ##### INSTANCE METHODS #####
34
+
35
+ # Returns an array of hashes representing barcodes. Each hash has the
36
+ # following keys:
37
+ # :text => String with the plain text version of the barcode
38
+ # :image_src => String with the Base64-encoded barcode PNG, prefixed with
39
+ # the necessary inline image HTML prefix; intended to be
40
+ # the entire value needed for an IMG tag's SRC attribute
41
+ # :last => Set to true for last barcode (to help rendering)
42
+ # It gets the actual content for the hashes from the #get_texts method,
43
+ # and then adds one more barcode representing the wrapped object's base
44
+ # class name.
45
+ def barcode_infos
46
+ @barcode_infos ||= begin
47
+ texts = get_texts
48
+ texts << ("#{base_class_name}/") if base_class_name
49
+
50
+ infos = texts.map do |text|
51
+ { text: text, image_src: barcode_inline_image_src(text) }
52
+ end
53
+ infos.last[:last] = true
54
+ infos
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # All subclasses must overwrite this method to return an array of
61
+ # strings to generate barcodes for. The strings should already be formatted
62
+ # (upcased, invalid chars removed, max length enforced, etc.).
63
+ def get_texts # rubocop:disable Naming/AccessorMethodName
64
+ raise "Subclasses of HasHelpers::BarcodeBasePresenter must implement #get_texts."
65
+ end
66
+
67
+ # Returns a String that is the wrapped object's base class's name. Overwrite
68
+ # this in the subclass if you want it to return a different String, or set
69
+ # it to return nil if you don't want this included in the barcodes.
70
+ def base_class_name
71
+ @base_class_name ||= wrapped_object.class.base_class.name
72
+ end
73
+
74
+ # Returns a copy of the string passed in with the following changes:
75
+ # 1. Removes all non-alphanumeric chars. Note that this also removes
76
+ # underscores, even though regex considers those alphanumeric - i.e.
77
+ # we only preserve a-z, A-Z, and 0-9.
78
+ # 2. Upcases the string.
79
+ # 3. If a maximum length is passed in, truncates the string to be no longer
80
+ # than that.
81
+ # If the string passed in is nil, returns an empty string.
82
+ def format_alphanumeric(str, maximum_length = nil)
83
+ return "" if str.blank?
84
+
85
+ formatted_string = str.upcase.gsub(/[^a-zA-Z\d]/, "")
86
+ formatted_string = formatted_string[0, maximum_length] if maximum_length
87
+ formatted_string
88
+ end
89
+
90
+ # Returns a copy of the string passed in with the following changes:
91
+ # 1. Removes all non-numeric chars.
92
+ # 2. If a maximum length is passed in, truncates the string to be no longer
93
+ # than that.
94
+ # If the string passed in is nil, returns an empty string.
95
+ def format_numeric(str, maximum_length = nil)
96
+ return "" if str.blank?
97
+
98
+ formatted_string = str.gsub(/[\D]/, "")
99
+ formatted_string = formatted_string[0, maximum_length] if maximum_length
100
+ formatted_string
101
+ end
102
+
103
+ def barcode_inline_image_src(text)
104
+ "data:image/png;base64,#{barcode_base64(text)}"
105
+ end
106
+
107
+ # Takes the text passed in, returns a base64 string representing the PNG
108
+ # data for the barcode representation of that text.
109
+ def barcode_base64(text)
110
+ Base64.encode64(::Barby::Code128B.new(text).to_png(xdim: 2, height: 36))
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,100 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module HasHelpers
5
+ class BasePresenter
6
+ module Routing
7
+ # Returns an object which has the URL helpers for the current Rails application.
8
+ def self.routes
9
+ @routes ||= Class.new do
10
+ include Rails.application.routes.url_helpers # Including the helpers will mix in the polymorphic url helper methods in addition to the regular url helpers.
11
+ end.new
12
+ end
13
+ end
14
+
15
+ include ::HasHelpers::Attributes
16
+ attr_accessor :wrapped_object
17
+ attr_writer :errors
18
+
19
+ # Accepts an object or collection of objects and returns an
20
+ # Array of presenter instances wrapping each object.
21
+ def self.wrap(*args, **options)
22
+ if args.length == 1 && args[0].respond_to?(:map)
23
+ args[0].map do |data|
24
+ data_args = ::Array[data]
25
+ options = data_args.last.is_a?(Hash) ? data_args.pop : {}
26
+ new(*data_args, options)
27
+ end
28
+ else
29
+ [new(*args, **options)]
30
+ end
31
+ end
32
+
33
+ # Merges options with each element of the collection argument, and then calls
34
+ # .wrap passing the result
35
+ def self.wrap_with_options(collection, **options)
36
+ self.wrap(collection.lazy.map { |values| values.reverse_merge(options) })
37
+ end
38
+
39
+ def initialize(*args)
40
+ attrs = args.last.is_a?(Hash) ? args.pop : {}
41
+ self.wrapped_object = args.first
42
+ super(attrs) # run Attributes initializer
43
+ end
44
+
45
+ def ==(other)
46
+ other.is_a?(self.class) && instance_variables.all? do |ivar|
47
+ instance_variable_get(ivar) == other.instance_variable_get(ivar)
48
+ end
49
+ end
50
+
51
+ def error_on(accessor_name, include_dot_keys: true)
52
+ return if errors.blank?
53
+
54
+ messages =
55
+ if errors.respond_to?(:messages)
56
+ errors.messages
57
+ else
58
+ errors
59
+ end
60
+
61
+ if include_dot_keys
62
+ keys = messages.keys.grep(/\A#{Regexp.quote(accessor_name.to_s)}(\z|\.)/)
63
+ keys.flat_map { |key| messages[key] }
64
+ else
65
+ messages[accessor_name.to_sym] || messages[accessor_name.to_s]
66
+ end
67
+ end
68
+
69
+ def errors
70
+ @errors || wrapped_object_errors || {}
71
+ end
72
+
73
+ # Convenience method for accessing application routes.
74
+ # === Examples
75
+ # routes.advisor_path(@advisor)
76
+ # routes.polymorphic_url([@advisor, @payment])
77
+ delegate :routes, to: :'::HasHelpers::BasePresenter::Routing'
78
+
79
+ private
80
+
81
+ def method_missing(name, *args, &block)
82
+ if (accessor_name = name.to_s[/\Ahas_error_on_(.*)\Z/, 1]) # Check for names such as `has_error_on_field_name`
83
+ error_on(accessor_name).present?
84
+ elsif (accessor_name = name.to_s[/\Ahas_(.*)\Z/, 1]) && respond_to?(accessor_name) # Check for names such as `has_some_method` and strip the leading `has_` portion.
85
+ result = send(accessor_name)
86
+ if result.is_a?(Enumerator) # Enumerable#present? does not return the expected value, e.g. `[].to_enum.present? #=> true`
87
+ result.size && result.size > 0
88
+ else
89
+ result.present?
90
+ end
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ def wrapped_object_errors
97
+ wrapped_object && wrapped_object.respond_to?(:errors) && wrapped_object.errors
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,28 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ class HasHelpers::CacheableItem
5
+ attr_writer :cache_key
6
+ attr_accessor :promised_item
7
+
8
+ def initialize(key, item = nil, &block)
9
+ self.cache_key = key
10
+ self.promised_item = item || block
11
+ end
12
+
13
+ def item
14
+ ::HasHelpers::ItemPresenter.new(
15
+ case promised_item
16
+ when Proc then promised_item[]
17
+ else promised_item
18
+ end
19
+ )
20
+ end
21
+
22
+ def cache_key
23
+ case @cache_key
24
+ when ::ActiveRecord::Base then "#{@cache_key.class.name}/#{@cache_key.id}-#{@cache_key.updated_at.to_i}#{@cache_key['cache_key']}"
25
+ else @cache_key
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,52 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class HasHelpers::ItemPresenter < ::HasHelpers::BasePresenter
5
+ attr_accessor :selected, :is_heading, :name, :status, :highlight, :tag, :emphasized
6
+ attr_writer :details, :service, :image_service, :icon, :items,
7
+ :title, # Value used for the HTML title attribute. When set explicitly to `true` (`TrueClass`) then the value returned by `name` will be used as the title.
8
+ :data # Set with a hash of data-attribute key/value pairs.
9
+
10
+ def details
11
+ Array[*@details]
12
+ end
13
+
14
+ def service
15
+ @service && @service.to_service
16
+ end
17
+
18
+ def image_service
19
+ @image_service && @image_service.to_service
20
+ end
21
+
22
+ def cache_key
23
+ nil
24
+ end
25
+
26
+ def item
27
+ self
28
+ end
29
+
30
+ def icon
31
+ @icon && @icon.to_icon
32
+ end
33
+
34
+ def items
35
+ ::HasHelpers::ItemPresenter.new(items: @items) if @items
36
+ end
37
+
38
+ def title
39
+ case @title
40
+ when TrueClass then name
41
+ else @title
42
+ end
43
+ end
44
+
45
+ def attributes
46
+ (@data || {}).tap do |data_hash|
47
+ data_hash.keys.each do |k|
48
+ data_hash["data-#{k}"] = data_hash.delete(k)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class HasHelpers::ItemsPresenter < ::HasHelpers::BasePresenter
5
+ attr_accessor :skin
6
+ attr_writer :items, :attributes
7
+
8
+ def items(i = @items)
9
+ @memoized_items ||= i.map do |item| # rubocop:disable Naming/MemoizedInstanceVariableName
10
+ case item
11
+ when ::HasHelpers::CacheableItem
12
+ item
13
+ else
14
+ ::HasHelpers::ItemPresenter.new(item)
15
+ end
16
+ end
17
+ end
18
+
19
+ def attributes
20
+ @attributes || []
21
+ end
22
+
23
+ def cache_key
24
+ @cache_key ||= if @cache_key_is_memoized
25
+ @cache_key_memoized
26
+ else
27
+ @cache_key_is_memoized = true
28
+ @cache_key_memoized = if (cache_key_items = items.map(&:cache_key)).all?
29
+ Digest::MD5.hexdigest cache_key_items.join
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::ActionPresenter < ::HasHelpers::BasePresenter
4
+ attr_accessor :service, # href attribute
5
+ :title, # anchor title attribute
6
+ :icon, # Font awesome icon class, icon- prefix omitted, e.g. "angle-down" or "search"
7
+ :data # Collection of data attributes for action
8
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HasHelpers::Resource::CellPresenter < ::HasHelpers::BasePresenter
4
+ # Content attributes +value+, +resource+ and +tags+. These attributes should be used exclusively.
5
+ attr_writer :value, # +value+ will be displayed as the content of the current cell.
6
+ :resource # Use +resource+ instead of +value+ when the target should be automatically wrapped in an InfoPresenter.
7
+ attr_accessor :tags # +tags+ will generate an unordered list using the collection it is set to.
8
+
9
+ attr_accessor :blank, # When set to true no output is generated for the content of the current cell. Without this option
10
+ # a nil value will be formatted to display "none" as the cell content.
11
+ :is_primary,
12
+ :primary_title, # E.g. the wording of the indication that this object is a favorite
13
+ :service, # When set the cell content is wrapped with an anchor tag which links to the given service URL.
14
+ :service_title, # E.g. used for link title attributes
15
+ :is_service_external, # When set to true the link for the cell (if any) should be externalized.
16
+ :is_header, # E.g, If set to true the cell will be rendered within a <TH> tag instead of <TD>
17
+ :warning, # When set to true an warning sign icon is displayed along with the cell content.
18
+ :is_text, # Used to identify cells with long text values which may need extra styling (or formatting?)
19
+ :colspan
20
+ attr_writer :template, # Setting template will cause rendering to use a custom partial
21
+ :current_user # Used to pass through to presenters for content
22
+
23
+ # Returns the content from either +value+ or resource.
24
+ def content
25
+ if @value.nil?
26
+ resource
27
+ elsif @value.present?
28
+ @value
29
+ end
30
+ end
31
+
32
+ def template
33
+ @template.nil? ? detect_template_from_value : @template
34
+ end
35
+
36
+ private
37
+
38
+ def detect_template_from_value
39
+ case content
40
+ when ::HasHelpers::Resource::InfoPresenter then "info"
41
+ end
42
+ end
43
+
44
+ # Return the resource object which was set, wrapped in an InfoPresenter.
45
+ def resource
46
+ case @resource
47
+ when ::HasHelpers::Resource::InfoPresenter, NilClass then @resource
48
+ when Hash then ::HasHelpers::Resource::InfoPresenter.new(@resource.reverse_merge(current_user: @current_user))
49
+ else ::HasHelpers::Resource::InfoPresenter.new(@resource, current_user: @current_user)
50
+ end
51
+ end
52
+ end