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,65 @@
1
+ require "rails_helper"
2
+
3
+ describe ::Flattener::Column::Types do
4
+ describe ".sql_type_to_type" do # Just testing cases which are more complicated than a 1-to-1 mapping
5
+ it "matches all varchars as string type" do
6
+ aggregate_failures do
7
+ expect(subject.sql_type_to_type("character varying")).to eq(described_class::STRING)
8
+ expect(subject.sql_type_to_type("character varying(255)")).to eq(described_class::STRING)
9
+ end
10
+ end
11
+
12
+ it "matches string type" do
13
+ aggregate_failures do
14
+ expect(subject.sql_type_to_type("string")).to eq(described_class::STRING)
15
+ end
16
+ end
17
+
18
+ describe "numerics" do
19
+ it "matches currency type" do
20
+ aggregate_failures do
21
+ expect(subject.sql_type_to_type("numeric(7,2)")).to eq(described_class::CURRENCY)
22
+ expect(subject.sql_type_to_type("numeric(12,2)")).to eq(described_class::CURRENCY)
23
+ expect(subject.sql_type_to_type("numeric(20,5)")).to eq(described_class::CURRENCY)
24
+ end
25
+ end
26
+
27
+ it "matches percent type" do
28
+ aggregate_failures do
29
+ expect(subject.sql_type_to_type("numeric(6,3)")).to eq(described_class::PERCENT)
30
+ expect(subject.sql_type_to_type("numeric(9,6)")).to eq(described_class::PERCENT)
31
+ end
32
+ end
33
+
34
+ it "matches plain jane decimal type" do
35
+ aggregate_failures do
36
+ expect(subject.sql_type_to_type("numeric(4,2)")).to eq(described_class::DECIMAL)
37
+ expect(subject.sql_type_to_type("numeric(5,3)")).to eq(described_class::DECIMAL)
38
+ end
39
+ end
40
+
41
+ it "matches numeric without scale and precision" do
42
+ # FIXME: Remove this spec once all numeric columns have scale and precision set. *
43
+ expect(subject.sql_type_to_type("numeric")).to eq(described_class::DECIMAL)
44
+ end
45
+ end
46
+
47
+ describe "matches array type" do
48
+ it { expect(subject.sql_type_to_type("Array")).to eq(described_class::ARRAY) }
49
+ it { expect(subject.sql_type_to_type("ARRAY")).to eq(described_class::ARRAY) }
50
+ it { expect(subject.sql_type_to_type("array")).to eq(described_class::ARRAY) }
51
+ it { expect(subject.sql_type_to_type(:array)).to eq(described_class::ARRAY) }
52
+ end
53
+
54
+ it "errors like a boss when no type is matched" do
55
+ aggregate_failures do
56
+ # FIXME: Revert this once all numeric columns have scale and precision set. *
57
+ # expect { subject.sql_type_to_type("numeric") }.to raise_error(::ArgumentError, /No type matches SQL type/) # decimal is missing scale qualification
58
+ expect { subject.sql_type_to_type("numeric(9)") }.to raise_error(::ArgumentError, /No type matches SQL type/) # decimal is missing precision qualification
59
+
60
+ expect { subject.sql_type_to_type("varchar") }.to raise_error(::ArgumentError, /No type matches SQL type/) # varchar is specified differently
61
+ expect { subject.sql_type_to_type("invalid") }.to raise_error(::ArgumentError, /No type matches SQL type/)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,53 @@
1
+ require "rails_helper"
2
+
3
+ describe ::HasHelpers::ActiveRecord::Base do
4
+ subject { FactoryBot.create(:organization) }
5
+ let(:nested_resource) { FactoryBot.create(:event) }
6
+
7
+ describe "#to_service" do
8
+ it { expect(subject.to_service).to be_a(::Service) }
9
+ it { expect(subject.to_service.url).to eq("/organizations/#{ subject.id }") }
10
+ it { expect(::Organization.new.to_service.to_s).to eq("") }
11
+
12
+ context "nested resource" do
13
+ it { expect { nested_resource.to_service }.to raise_error(::HasHelpers::ActiveRecord::ServiceError, /event_path/) }
14
+ end
15
+ end
16
+
17
+ describe "#to_renderable" do
18
+ it { expect(subject.to_renderable).to eq(subject.to_service) }
19
+ it { expect(::Event.new.to_renderable).to eq(::HasHelpers::TextNode.new("")) }
20
+
21
+ context "nested resource" do
22
+ it { expect(nested_resource.to_renderable).to eq(nested_resource.name.to_text_node) }
23
+ end
24
+
25
+ context "with renderable proc" do
26
+ before(:all) do
27
+ @stashed_renderable_proc = described_class.to_renderable_proc
28
+ described_class.set_renderable_proc do |record|
29
+ case record
30
+ when ::Event
31
+ record.name.to_s.to_service
32
+ when ::Organization
33
+ record.name.to_s.to_text_node
34
+ end
35
+ end
36
+ end
37
+
38
+ after(:all) do
39
+ described_class.set_renderable_proc(@stashed_renderable_proc)
40
+ end
41
+
42
+ context "for explicitly handled cases" do
43
+ it { expect(::Event.new.to_renderable).to be_a(::Service) }
44
+ it { expect(::Organization.new.to_renderable).to be_a(::HasHelpers::TextNode) }
45
+ end
46
+
47
+ it "defaults to the normal behavior" do
48
+ expect(::User.new.to_renderable).to be_a(::Service) # has matching route
49
+ expect(::Meetup.new.to_renderable).to be_a(::HasHelpers::TextNode) # no matching route
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,498 @@
1
+ require "rails_helper"
2
+
3
+ # TODO: Set up and test against database triggers which correspond to the date range model validations *
4
+ describe ::HasHelpers::ActiveRecord::DateRange do
5
+ describe "#has_valid_date_range" do
6
+ subject { FactoryBot.build(:basic_schedule) }
7
+
8
+ context "end_date sanity check" do
9
+ it "validates when end_date is nil" do
10
+ subject.end_date = nil
11
+ subject.validate
12
+ expect(subject.errors[:end_date]).to be_empty
13
+ end
14
+
15
+ it "validates when end_date is after start_date" do
16
+ subject.end_date = subject.start_date + 1.day
17
+ subject.validate
18
+ expect(subject.errors[:end_date]).to be_empty
19
+ end
20
+
21
+ it "validates when end_date equals start_date" do
22
+ subject.end_date = subject.start_date
23
+ subject.validate
24
+ expect(subject.errors[:end_date]).to be_empty
25
+ end
26
+
27
+ it "fails when end_date is before start_date" do
28
+ subject.end_date = subject.start_date - 1.day
29
+ subject.validate
30
+ expect(subject.errors[:end_date]).to include(described_class::END_DATE_SANITY_ERR_MSG % ["End Date", "Start Date"])
31
+ end
32
+ end
33
+
34
+ context "adds date range accessor method" do
35
+ context "returns date range" do
36
+ it do
37
+ start_date = FactoryBot.generate(:past_date)
38
+ end_date = FactoryBot.generate(:future_date)
39
+ subject.start_date = start_date
40
+ subject.end_date = end_date
41
+ expect(subject.date_range).to eq(start_date..end_date)
42
+ end
43
+
44
+ it "with no end date" do
45
+ start_date = FactoryBot.generate(:past_date)
46
+ subject.start_date = start_date
47
+ subject.end_date = nil
48
+ expect(subject.date_range).to eq(start_date..Date::Infinity.new)
49
+ end
50
+
51
+ it "with no start date" do
52
+ end_date = FactoryBot.generate(:future_date)
53
+ subject.start_date = nil
54
+ subject.end_date = end_date
55
+ expect(subject.date_range).to eq(-Date::Infinity.new..end_date)
56
+ end
57
+
58
+ it "with no dates" do
59
+ subject.start_date = nil
60
+ subject.end_date = nil
61
+ expect(subject.date_range).to eq(-Date::Infinity.new..Date::Infinity.new)
62
+ end
63
+ end
64
+
65
+ context "with name set by :as option" do
66
+ it do
67
+ start_date = FactoryBot.generate(:past_date)
68
+ end_date = FactoryBot.generate(:future_date)
69
+ subject.start_date = start_date
70
+ subject.end_date = end_date
71
+ expect(subject.epoch).to eq(start_date..end_date)
72
+ end
73
+
74
+ it "with no end date" do
75
+ start_date = FactoryBot.generate(:past_date)
76
+ subject.start_date = start_date
77
+ subject.end_date = nil
78
+ expect(subject.epoch).to eq(start_date..Date::Infinity.new)
79
+ end
80
+
81
+ it "with no start date" do
82
+ end_date = FactoryBot.generate(:future_date)
83
+ subject.start_date = nil
84
+ subject.end_date = end_date
85
+ expect(subject.epoch).to eq(-Date::Infinity.new..end_date)
86
+ end
87
+
88
+ it "with no dates" do
89
+ subject.start_date = nil
90
+ subject.end_date = nil
91
+ expect(subject.epoch).to eq(-Date::Infinity.new..Date::Infinity.new)
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#has_distinct_date_range" do
98
+ let(:user) { FactoryBot.build(:user) }
99
+ let(:a) { user.schedules.build(FactoryBot.attributes_for(:schedule, :with_end_date).except(:user_id)) }
100
+ let(:b) { user.schedules.build(FactoryBot.attributes_for(:schedule, :with_end_date).except(:user_id)) }
101
+
102
+ ## case 1: <--- [A] --->
103
+ ## (don't care about B; always overlaps)
104
+ describe "when A is open-ended on both ends" do
105
+ it "should overlap" do
106
+ a.start_date = a.end_date = nil
107
+ aggregate_failures do
108
+ expect(a.date_range_overlaps?(b)).to be_truthy
109
+ expect(b.date_range_overlaps?(a)).to be_truthy
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+ describe "when A is open-ended on the left" do
116
+ ## case 2a: <--- [A] ------|
117
+ ## <--- [B] ---|
118
+ ## case 2b: <--- [A] ------|
119
+ ## <--- [B] ---------|
120
+ describe "and B is open-ended on the left" do
121
+ it "should overlap" do
122
+ a.start_date = b.start_date = nil
123
+ aggregate_failures do
124
+ expect(a.date_range_overlaps?(b)).to be_truthy
125
+ expect(b.date_range_overlaps?(a)).to be_truthy
126
+ end
127
+ end
128
+ end
129
+ describe "and B's start date" do
130
+ ## case 3: <--- [A] ------|
131
+ ## |--- [B] ---|
132
+ describe "is before A's end date" do
133
+ it "should overlap" do
134
+ a.start_date = nil
135
+ b.start_date = a.end_date - (rand(5) + 1).days
136
+ # b.end_date = b.start_date + FactoryBot.generate(:little_interval) unless b.end_date.nil?
137
+ b.end_date = b.start_date + (rand(5) + 1).days unless b.end_date.nil?
138
+ aggregate_failures do
139
+ expect(a.date_range_overlaps?(b)).to be_truthy
140
+ expect(b.date_range_overlaps?(a)).to be_truthy
141
+ end
142
+ end
143
+ end
144
+ ## case 4: <--- [A] ------|
145
+ ## |--- [B] ---|
146
+ describe "is after A's end date" do
147
+ it "should not overlap" do
148
+ a.start_date = nil
149
+ b.start_date = a.end_date + (rand(5) + 1).days
150
+ # b.end_date = b.start_date + FactoryBot.generate(:little_interval) unless b.end_date.nil?
151
+ b.end_date = b.start_date + (rand(5) + 1).days unless b.end_date.nil?
152
+ aggregate_failures do
153
+ expect(a.date_range_overlaps?(b)).to be_falsey
154
+ expect(b.date_range_overlaps?(a)).to be_falsey
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ describe "when A is open-ended on the right" do
162
+ ## case 5a: |------ [A] --->
163
+ ## |--------- [B] --->
164
+ ## case 5b: |------ [A] --->
165
+ ## |--- [B] --->
166
+ describe "and B is open-ended on the right" do
167
+ it "should overlap" do
168
+ a.end_date = b.end_date = nil
169
+ expect(a.date_range_overlaps?(b)).to be_truthy
170
+ expect(b.date_range_overlaps?(a)).to be_truthy
171
+ end
172
+ end
173
+ describe "and B's end date" do
174
+ ## case 6: |--- [A] --->
175
+ ## |--- [B] ---|
176
+ describe "is before A's start date" do
177
+ it "should not overlap" do
178
+ a.end_date = nil
179
+ b.end_date = a.start_date - (rand(5) + 1).days
180
+ # b.start_date = b.end_date - FactoryBot.generate(:little_interval) unless b.start_date.nil?
181
+ b.start_date = b.end_date - (rand(5) + 1).days
182
+ aggregate_failures do
183
+ expect(a.date_range_overlaps?(b)).to be_falsey
184
+ expect(b.date_range_overlaps?(a)).to be_falsey
185
+ end
186
+ end
187
+ end
188
+ ## case 7: |--- [A] --->
189
+ ## |--- [B] ---|
190
+ describe "is after A's start date" do
191
+ it "should overlap" do
192
+ a.end_date = nil
193
+ b.end_date = a.start_date + (rand(5) + 1).days
194
+ # b.start_date = b.end_date - FactoryBot.generate(:little_interval) unless b.start_date.nil?
195
+ b.start_date = b.end_date - (rand(5) + 1).days
196
+ aggregate_failures do
197
+ expect(a.date_range_overlaps?(b)).to be_truthy
198
+ expect(b.date_range_overlaps?(a)).to be_truthy
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ describe "when A is bounded" do
206
+ ## case 8: |------ [A] ------|
207
+ ## |--- [B] ---|
208
+ describe "and B is entirely within A" do
209
+ it "should overlap" do
210
+ a.start_date = b.start_date - (rand(5) + 1).days
211
+ a.end_date = b.end_date + (rand(5) + 1).days
212
+ aggregate_failures do
213
+ expect(a.date_range_overlaps?(b)).to be_truthy
214
+ expect(b.date_range_overlaps?(a)).to be_truthy
215
+ end
216
+ end
217
+ end
218
+ ## case 9: |--- [A] ------|
219
+ ## |------ [B] ---|
220
+ describe "and B overlaps A" do
221
+ it "should overlap" do
222
+ b.start_date = a.start_date - (rand(5) + 1).days
223
+ # a.end_date = b.end_date + (rand(5) + 1).days
224
+ aggregate_failures do
225
+ expect(a.date_range_overlaps?(b)).to be_truthy
226
+ expect(b.date_range_overlaps?(a)).to be_truthy
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ describe "date range validation" do
234
+ context do
235
+ # Set up a schedule (subject) which has the same attributes as another
236
+ # schedule (other) and the same owner (user).
237
+ let(:user) { FactoryBot.build(:user) }
238
+ let(:schedule_attrs) { FactoryBot.attributes_for(:schedule, :with_end_date) }
239
+ let!(:other) { user.schedules.build(schedule_attrs.except(:user_id)) }
240
+ subject! { user.schedules.build(schedule_attrs.except(:user_id)) }
241
+
242
+ it "fails when date ranges overlap" do
243
+ subject.validate
244
+ other.validate
245
+ aggregate_failures do
246
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
247
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
248
+ end
249
+ end
250
+
251
+ it "succeeds when date ranges do NOT overlap" do
252
+ subject.start_date = other.end_date + 1
253
+ subject.end_date = nil
254
+ subject.validate
255
+ other.validate
256
+ aggregate_failures do
257
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
258
+ expect(other.errors[:start_date]).to_not include(/must be unique within the given date range/)
259
+ end
260
+ end
261
+
262
+ it "does not add errors if the object is marked for destruction" do
263
+ subject.mark_for_destruction
264
+ subject.validate
265
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
266
+ end
267
+ end
268
+
269
+ context do
270
+ # Set up an event (subject) which has the same attributes as another
271
+ # event (other) and the same owner (user).
272
+ let(:user) { FactoryBot.build(:user) }
273
+ let(:event_attrs) { FactoryBot.attributes_for(:event, :with_end_date, :with_manager, :with_schedule_type) }
274
+ let!(:other) { user.events.build(event_attrs.except(:user_id)) }
275
+ subject! { user.events.build(event_attrs.except(:user_id)) }
276
+
277
+ it "fails when date ranges overlap" do
278
+ subject.validate
279
+ other.validate
280
+ aggregate_failures do
281
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
282
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
283
+ end
284
+ end
285
+
286
+ context "when strict scopes" do
287
+ it "differ it succeeds" do
288
+ subject.manager = other.manager.next
289
+ subject.validate
290
+ other.validate
291
+ aggregate_failures do
292
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
293
+ expect(other.errors[:start_date]).to_not include(/must be unique within the given date range/)
294
+ end
295
+ end
296
+
297
+ it "differ, and one is nil, it succeeds" do
298
+ aggregate_failures do
299
+ subject.manager = nil
300
+ subject.validate
301
+ other.validate
302
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
303
+ expect(other.errors[:start_date]).to_not include(/must be unique within the given date range/)
304
+
305
+ subject.manager = other.manager
306
+ other.manager = nil
307
+ subject.validate
308
+ other.validate
309
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
310
+ expect(other.errors[:start_date]).to_not include(/must be unique within the given date range/)
311
+ end
312
+ end
313
+
314
+ it "are equally nil it fails" do
315
+ subject.manager = other.manager = nil
316
+ subject.validate
317
+ other.validate
318
+ aggregate_failures do
319
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
320
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
321
+ end
322
+ end
323
+ end
324
+
325
+ context "when nullable scopes" do
326
+ it "differ, but are not nil, it succeeds" do
327
+ subject.schedule_type = ::Event::SCHEDULE_TYPES.reject { |t| t == other.schedule_type }.sample
328
+ subject.validate
329
+ other.validate
330
+ aggregate_failures do
331
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
332
+ expect(other.errors[:start_date]).to_not include(/must be unique within the given date range/)
333
+ end
334
+ end
335
+
336
+ it "differ and at least one is nil, it fails" do
337
+ aggregate_failures do
338
+ subject.schedule_type = nil
339
+ subject.validate
340
+ other.validate
341
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
342
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
343
+
344
+ subject.schedule_type = other.schedule_type
345
+ other.schedule_type = nil
346
+ subject.validate
347
+ other.validate
348
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
349
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
350
+
351
+ subject.schedule_type = other.schedule_type = nil
352
+ subject.validate
353
+ other.validate
354
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
355
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
356
+ end
357
+ end
358
+ end
359
+
360
+ it "does not add errors if the object is marked for destruction" do
361
+ subject.mark_for_destruction
362
+ subject.validate
363
+ expect(subject.errors[:start_date]).to_not include(/must be unique within the given date range/)
364
+ end
365
+ end
366
+
367
+ context "with scoped association" do
368
+ # Set up an meetup (subject) which has the same attributes as another
369
+ # meetup (other) and the same owner (user).
370
+ let(:user) { FactoryBot.build(:user) }
371
+ let(:meetup_attrs) { FactoryBot.attributes_for(:meetup, :with_end_date) }
372
+ context do
373
+ let!(:other) { user.meetups.build(meetup_attrs.except(:user_id)) }
374
+
375
+ context "records built on different associations" do
376
+ subject! { user.current_meetups.build(meetup_attrs.except(:user_id)) }
377
+
378
+ it "fails for both siblings" do
379
+ subject.validate
380
+ other.validate
381
+ aggregate_failures do
382
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
383
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
384
+ end
385
+ end
386
+ end
387
+
388
+ context "records built on the base association" do
389
+ subject! { user.meetups.build(meetup_attrs.except(:user_id)) }
390
+
391
+ it "fails for both siblings" do
392
+ subject.validate
393
+ other.validate
394
+ aggregate_failures do
395
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
396
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
397
+ end
398
+ end
399
+ end
400
+ end
401
+
402
+ context "records built on the scoped association" do
403
+ let!(:other) { user.current_meetups.build(meetup_attrs.except(:user_id)) }
404
+ subject! { user.current_meetups.build(meetup_attrs.except(:user_id)) }
405
+
406
+ it "fails for both siblings" do
407
+ subject.validate
408
+ other.validate
409
+ aggregate_failures do
410
+ expect(subject.errors[:start_date]).to include(/must be unique within the given date range/)
411
+ expect(other.errors[:start_date]).to include(/must be unique within the given date range/)
412
+ end
413
+ end
414
+ end
415
+ end
416
+
417
+ it "the default siblings proc does not throw an exception if owner is nil" do
418
+ subject = FactoryBot.build(:schedule, user: nil)
419
+ expect{ subject.validate }.to_not raise_error
420
+ end
421
+ end
422
+
423
+ before(:each) do
424
+ Schedule.all.delete_all
425
+ end
426
+
427
+ describe "generated scope" do
428
+ let!(:schedule_user) { FactoryBot.create(:user) }
429
+ let!(:schedule_a) { FactoryBot.build(:schedule, user: schedule_user, start_date: "2015-01-01", end_date: "2015-11-19").tap { |s| s.save!(validate: false) } }
430
+ let!(:schedule_b) { FactoryBot.build(:schedule, user: schedule_user, start_date: "2015-10-15", end_date: "2015-11-21").tap { |s| s.save!(validate: false) } }
431
+ let!(:schedule_c) { FactoryBot.build(:schedule, user: schedule_user, start_date: "2015-11-16", end_date: nil).tap { |s| s.save!(validate: false) } }
432
+
433
+ it do
434
+ aggregate_failures do
435
+ Timecop.freeze("2015-11-19") do
436
+ expect(Schedule.current).to contain_exactly(schedule_a, schedule_b, schedule_c)
437
+ end
438
+ expect(Schedule.current("2014-11-19")).to be_empty
439
+ expect(Schedule.current("2015-01-01")).to contain_exactly(schedule_a)
440
+ expect(Schedule.current("2015-11-08")).to contain_exactly(schedule_a, schedule_b)
441
+ expect(Schedule.current("2015-11-17")).to contain_exactly(schedule_a, schedule_b, schedule_c)
442
+ expect(Schedule.current("2015-11-21")).to contain_exactly(schedule_b, schedule_c)
443
+ expect(Schedule.current("2015-12-09")).to contain_exactly(schedule_c)
444
+ end
445
+ end
446
+
447
+ it "is named using the +:as+ option" do
448
+ aggregate_failures do
449
+ Timecop.freeze("2015-11-19") do
450
+ expect(Schedule.current_for_epoch).to contain_exactly(schedule_a, schedule_b, schedule_c)
451
+ end
452
+ expect(Schedule.current_for_epoch("2014-11-19")).to be_empty
453
+ expect(Schedule.current_for_epoch("2015-01-01")).to contain_exactly(schedule_a)
454
+ expect(Schedule.current_for_epoch("2015-11-08")).to contain_exactly(schedule_a, schedule_b)
455
+ expect(Schedule.current_for_epoch("2015-11-17")).to contain_exactly(schedule_a, schedule_b, schedule_c)
456
+ expect(Schedule.current_for_epoch("2015-11-21")).to contain_exactly(schedule_b, schedule_c)
457
+ expect(Schedule.current_for_epoch("2015-12-09")).to contain_exactly(schedule_c)
458
+ end
459
+ end
460
+
461
+ it "is named using the +:scope_name+ option" do
462
+ aggregate_failures do
463
+ Timecop.freeze("2015-11-19") do
464
+ expect(Schedule.range_in).to contain_exactly(schedule_a, schedule_b, schedule_c)
465
+ end
466
+ expect(Schedule.range_in("2014-11-19")).to be_empty
467
+ expect(Schedule.range_in("2015-01-01")).to contain_exactly(schedule_a)
468
+ expect(Schedule.range_in("2015-11-08")).to contain_exactly(schedule_a, schedule_b)
469
+ expect(Schedule.range_in("2015-11-17")).to contain_exactly(schedule_a, schedule_b, schedule_c)
470
+ expect(Schedule.range_in("2015-11-21")).to contain_exactly(schedule_b, schedule_c)
471
+ expect(Schedule.range_in("2015-12-09")).to contain_exactly(schedule_c)
472
+ end
473
+ end
474
+ end
475
+
476
+ describe "normalization" do
477
+ it "sets start_date to current date when nil" do
478
+ subject = FactoryBot.build(:meetup, start_date: nil)
479
+ aggregate_failures do
480
+ expect(subject.start_date).to be_nil
481
+ Timecop.freeze do
482
+ subject.validate # Runs before-validation normalizations
483
+ expect(subject.start_date).to eq(Date.current)
484
+ end
485
+ end
486
+ end
487
+
488
+ it "does not overwrite a set value for current_date" do
489
+ date = Date.new(2001, 11, 19)
490
+ subject = FactoryBot.build(:meetup, start_date: date)
491
+ aggregate_failures do
492
+ expect(subject.start_date).to eq(date)
493
+ subject.validate # Runs before-validation normalizations
494
+ expect(subject.start_date).to eq(date)
495
+ end
496
+ end
497
+ end
498
+ end