spree_cm_commissioner 2.8.15.pre.pre8 → 2.8.15

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 (295) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +20 -0
  3. data/.github/workflows/test_and_build_gem.yml +2 -1
  4. data/Gemfile.lock +2 -2
  5. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +8 -0
  6. data/app/controllers/concerns/spree_cm_commissioner/load_test_account_management.rb +80 -0
  7. data/app/controllers/concerns/spree_cm_commissioner/load_test_account_scope.rb +39 -0
  8. data/app/controllers/concerns/spree_cm_commissioner/load_test_bypassable.rb +29 -0
  9. data/app/controllers/concerns/spree_cm_commissioner/load_test_login_token_generation.rb +53 -0
  10. data/app/controllers/concerns/spree_cm_commissioner/order_concern.rb +5 -0
  11. data/app/controllers/concerns/spree_cm_commissioner/turnstile_protectable.rb +9 -7
  12. data/app/controllers/spree/admin/guests_controller.rb +4 -2
  13. data/app/controllers/spree/admin/import_new_orders_controller.rb +25 -0
  14. data/app/controllers/spree/admin/inventory_holds_controller.rb +21 -1
  15. data/app/controllers/spree/admin/system/load_test_accounts_controller.rb +24 -0
  16. data/app/controllers/spree/admin/system/load_test_flows_controller.rb +11 -0
  17. data/app/controllers/spree/admin/system/load_test_login_tokens_controller.rb +16 -0
  18. data/app/controllers/spree/admin/system/load_testing_controller.rb +9 -0
  19. data/app/controllers/spree/admin/system/maintenance_tasks_controller.rb +64 -0
  20. data/app/controllers/spree/admin/system/waiting_room_controller.rb +22 -0
  21. data/app/controllers/spree/admin/taxons_controller_decorator.rb +5 -0
  22. data/app/controllers/spree/admin/users_controller_decorator.rb +18 -0
  23. data/app/controllers/spree/api/chatrace/guests_controller.rb +1 -1
  24. data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +1 -0
  25. data/app/controllers/spree/api/v2/operator/guest_json_gzips_controller.rb +14 -4
  26. data/app/controllers/spree/api/v2/storefront/account/guest_dynamic_fields_controller.rb +19 -48
  27. data/app/controllers/spree/api/v2/storefront/account/mark_guest_info_complete_controller.rb +2 -2
  28. data/app/controllers/spree/api/v2/storefront/account/orders_controller_decorator.rb +10 -15
  29. data/app/controllers/spree/api/v2/storefront/account/saved_guests_controller.rb +65 -0
  30. data/app/controllers/spree/api/v2/storefront/account_checker_controller.rb +4 -0
  31. data/app/controllers/spree/api/v2/storefront/draft_orders_controller.rb +52 -0
  32. data/app/controllers/spree/api/v2/storefront/guests_controller.rb +13 -10
  33. data/app/controllers/spree/api/v2/storefront/order_histories_controller.rb +14 -3
  34. data/app/controllers/spree/api/v2/storefront/payment_methods_controller.rb +40 -0
  35. data/app/controllers/spree/api/v2/storefront/preview_sections_controller.rb +1 -7
  36. data/app/controllers/spree/api/v2/storefront/telegram_oauth_tokens_controller.rb +61 -0
  37. data/app/controllers/spree/api/v2/storefront/ticket_transfers_controller.rb +4 -3
  38. data/app/controllers/spree/api/v2/storefront/waiting_room_sessions_controller.rb +8 -1
  39. data/app/controllers/spree/api/v2/tenant/account/orders_controller.rb +1 -1
  40. data/app/controllers/spree/api/v2/tenant/account/saved_guests_controller.rb +70 -0
  41. data/app/controllers/spree/api/v2/tenant/draft_orders_controller.rb +50 -0
  42. data/app/controllers/spree/api/v2/tenant/episodes_controller.rb +3 -1
  43. data/app/controllers/spree/api/v2/tenant/guests_controller.rb +11 -21
  44. data/app/controllers/spree/api/v2/tenant/my_votes_controller.rb +51 -0
  45. data/app/controllers/spree/api/v2/tenant/order_histories_controller.rb +16 -3
  46. data/app/controllers/spree/api/v2/tenant/payment_methods_controller.rb +54 -0
  47. data/app/controllers/spree/api/v2/tenant/preview_products_controller.rb +1 -1
  48. data/app/controllers/spree/api/v2/tenant/preview_sections_controller.rb +1 -7
  49. data/app/controllers/spree/api/v2/tenant/show_people_controller.rb +1 -4
  50. data/app/controllers/spree/api/v2/tenant/show_person_assignments_controller.rb +4 -1
  51. data/app/controllers/spree/api/v2/tenant/voting_contestants_controller.rb +6 -3
  52. data/app/controllers/spree/api/v2/tenant/waiting_room_sessions_controller.rb +8 -1
  53. data/app/controllers/spree_cm_commissioner/admin/orders_controller_decorator.rb +9 -0
  54. data/app/controllers/spree_cm_commissioner/admin/variants_controller_decorator.rb +17 -0
  55. data/app/controllers/spree_cm_commissioner/api/v2/storefront/checkout_controller_decorator.rb +3 -3
  56. data/app/finders/spree_cm_commissioner/orders/find.rb +33 -3
  57. data/app/finders/spree_cm_commissioner/orders/find_by_all_state.rb +11 -0
  58. data/app/finders/spree_cm_commissioner/payment_methods/find.rb +59 -0
  59. data/app/finders/spree_cm_commissioner/routes/find.rb +1 -1
  60. data/app/interactors/spree_cm_commissioner/create_ticket.rb +7 -3
  61. data/app/interactors/spree_cm_commissioner/host_matcher.rb +6 -5
  62. data/app/interactors/spree_cm_commissioner/payment_incomplete_notification_sender.rb +25 -0
  63. data/app/interactors/spree_cm_commissioner/release_inventory_item_notification_sender.rb +24 -0
  64. data/app/interactors/spree_cm_commissioner/telegram_oauth_id_token_provider.rb +99 -0
  65. data/app/interactors/spree_cm_commissioner/telegram_oauth_token_exchanger.rb +71 -0
  66. data/app/interactors/spree_cm_commissioner/turnstile_token_validator.rb +43 -13
  67. data/app/interactors/spree_cm_commissioner/user_id_token_authenticator.rb +2 -5
  68. data/app/interactors/spree_cm_commissioner/user_password_authenticator.rb +23 -1
  69. data/app/interactors/spree_cm_commissioner/user_telegram_oauth_authenticator.rb +88 -0
  70. data/app/interactors/spree_cm_commissioner/waiting_guests_caller.rb +172 -20
  71. data/app/interactors/spree_cm_commissioner/waiting_room_latest_system_metadata_puller.rb +5 -3
  72. data/app/interactors/spree_cm_commissioner/waiting_room_session_creator.rb +56 -12
  73. data/app/jobs/concerns/spree_cm_commissioner/idempotent_job.rb +12 -0
  74. data/app/jobs/spree_cm_commissioner/cancel_import_order_job.rb +11 -0
  75. data/app/jobs/spree_cm_commissioner/idempotency_keys/prune_job.rb +20 -0
  76. data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_job.rb +21 -3
  77. data/app/jobs/spree_cm_commissioner/inventory_items/bulk_adjust_quantities_on_hold_job.rb +34 -3
  78. data/app/jobs/spree_cm_commissioner/maintenance_tasks/guest_data_fill_stage_batch_job.rb +28 -0
  79. data/app/jobs/spree_cm_commissioner/maintenance_tasks/refinalize_guests_batch_job.rb +36 -0
  80. data/app/jobs/spree_cm_commissioner/payment_incomplete_notification_job.rb +12 -0
  81. data/app/jobs/spree_cm_commissioner/telegram_alerts/order_integrity_check_job.rb +17 -0
  82. data/app/jobs/spree_cm_commissioner/waiting_guests_caller_job.rb +6 -1
  83. data/app/jobs/spree_cm_commissioner/waiting_room/publish_lobby_path_job.rb +17 -0
  84. data/app/jobs/spree_cm_commissioner/waiting_room/stamp_queue_positions_job.rb +14 -0
  85. data/app/jobs/spree_cm_commissioner/waiting_room_latest_system_metadata_puller_job.rb +1 -1
  86. data/app/mailers/spree/order_mailer_decorator.rb +4 -0
  87. data/app/models/concerns/spree_cm_commissioner/event_metadata.rb +17 -2
  88. data/app/models/concerns/spree_cm_commissioner/guest_data_fill_stage_concern.rb +82 -0
  89. data/app/models/concerns/spree_cm_commissioner/kyc_bitwise.rb +17 -0
  90. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +4 -0
  91. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +16 -2
  92. data/app/models/concerns/spree_cm_commissioner/line_items_filter_scope.rb +5 -3
  93. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +0 -1
  94. data/app/models/concerns/spree_cm_commissioner/order_holdable.rb +6 -0
  95. data/app/models/concerns/spree_cm_commissioner/order_qr_codeable.rb +39 -0
  96. data/app/models/concerns/spree_cm_commissioner/order_scopes.rb +5 -0
  97. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +57 -30
  98. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +4 -0
  99. data/app/models/concerns/spree_cm_commissioner/purchase_limitable.rb +59 -0
  100. data/app/models/concerns/spree_cm_commissioner/store_preference.rb +3 -0
  101. data/app/models/concerns/spree_cm_commissioner/tenant_preference.rb +2 -0
  102. data/app/models/concerns/spree_cm_commissioner/variant_options_concern.rb +0 -1
  103. data/app/models/spree_cm_commissioner/check_in_session.rb +36 -0
  104. data/app/models/spree_cm_commissioner/current.rb +11 -0
  105. data/app/models/spree_cm_commissioner/dynamic_field.rb +12 -0
  106. data/app/models/spree_cm_commissioner/exports/operator_guest_json_gzip.rb +26 -1
  107. data/app/models/spree_cm_commissioner/guest.rb +5 -144
  108. data/app/models/spree_cm_commissioner/guest_dynamic_field.rb +43 -71
  109. data/app/models/spree_cm_commissioner/homepage_section_relatable.rb +25 -0
  110. data/app/models/spree_cm_commissioner/idempotency_key.rb +21 -0
  111. data/app/models/spree_cm_commissioner/import.rb +2 -1
  112. data/app/models/spree_cm_commissioner/imported_order.rb +6 -0
  113. data/app/models/spree_cm_commissioner/imports/import_order.rb +21 -0
  114. data/app/models/spree_cm_commissioner/inventory_hold.rb +1 -1
  115. data/app/models/spree_cm_commissioner/line_item_decorator.rb +4 -3
  116. data/app/models/spree_cm_commissioner/maintenance_task.rb +10 -0
  117. data/app/models/spree_cm_commissioner/maintenance_tasks/event.rb +15 -14
  118. data/app/models/spree_cm_commissioner/maintenance_tasks/guest_data_fill_stage.rb +21 -0
  119. data/app/models/spree_cm_commissioner/notification.rb +1 -0
  120. data/app/models/spree_cm_commissioner/order_decorator.rb +38 -29
  121. data/app/models/spree_cm_commissioner/payment_decorator.rb +11 -0
  122. data/app/models/spree_cm_commissioner/payment_method_decorator.rb +2 -0
  123. data/app/models/spree_cm_commissioner/pricing_model_route.rb +8 -0
  124. data/app/models/spree_cm_commissioner/product_decorator.rb +4 -22
  125. data/app/models/spree_cm_commissioner/product_dynamic_field.rb +17 -0
  126. data/app/models/spree_cm_commissioner/request_guard.rb +19 -0
  127. data/app/models/spree_cm_commissioner/role_decorator.rb +52 -4
  128. data/app/models/spree_cm_commissioner/role_user_decorator.rb +11 -0
  129. data/app/models/spree_cm_commissioner/seat_layout.rb +12 -4
  130. data/app/models/spree_cm_commissioner/show.rb +3 -1
  131. data/app/models/spree_cm_commissioner/show_episode.rb +3 -1
  132. data/app/models/spree_cm_commissioner/show_person.rb +5 -1
  133. data/app/models/spree_cm_commissioner/show_person_assignment.rb +1 -1
  134. data/app/models/spree_cm_commissioner/taxon_ad_banner.rb +12 -0
  135. data/app/models/spree_cm_commissioner/taxon_decorator.rb +3 -0
  136. data/app/models/spree_cm_commissioner/tenant.rb +17 -6
  137. data/app/models/spree_cm_commissioner/trip.rb +18 -1
  138. data/app/models/spree_cm_commissioner/user_decorator.rb +67 -1
  139. data/app/models/spree_cm_commissioner/variant_options.rb +0 -4
  140. data/app/models/spree_cm_commissioner/vehicle_type.rb +1 -0
  141. data/app/models/spree_cm_commissioner/voting_contestant.rb +21 -7
  142. data/app/models/spree_cm_commissioner/waiting_room_session.rb +14 -0
  143. data/app/notifications/spree_cm_commissioner/order_general_notification.rb +15 -0
  144. data/app/overrides/spree/admin/orders/_order_actions/actions.html.erb.deface +7 -0
  145. data/app/overrides/spree/admin/orders/_search/payment_number_search_field.html.erb.deface +8 -0
  146. data/app/overrides/spree/admin/payment_methods/index/pagination.html.erb.deface +3 -0
  147. data/app/overrides/spree/admin/payment_methods/index/preserve_tab_in_search.html.erb.deface +4 -0
  148. data/app/overrides/spree/admin/products/_form/allow_gift_transfer.html.erb.deface +1 -1
  149. data/app/overrides/spree/admin/products/_form/allow_transfer.html.erb.deface +1 -1
  150. data/app/overrides/spree/admin/products/_form/enable_send_receipt.html.erb.deface +13 -0
  151. data/app/overrides/spree/admin/products/_form/enable_social_sharing_email.html.erb.deface +13 -0
  152. data/app/overrides/spree/admin/products/_form/enable_telegram_alert.html.erb.deface +14 -0
  153. data/app/overrides/spree/admin/shared/_order_summary/internal_note.html.erb.deface +23 -0
  154. data/app/overrides/spree/admin/shared/_order_summary/internal_note_modal.html.erb.deface +40 -0
  155. data/app/overrides/spree/admin/stores/_form/store_preferences.html.erb.deface +9 -0
  156. data/app/overrides/spree/admin/stores/_form/telegram_auth.html.erb.deface +73 -0
  157. data/app/overrides/spree/admin/taxons/_form/assets_form.html.erb.deface +10 -1
  158. data/app/overrides/spree/admin/variants/index/fixture_action.html.erb.deface +9 -0
  159. data/app/overrides/spree/admin/vendors/_form/term_of_use.html.erb.deface +6 -0
  160. data/app/queries/spree_cm_commissioner/event_chart_queries.rb +25 -9
  161. data/app/queries/spree_cm_commissioner/guest_searcher_query.rb +16 -3
  162. data/app/queries/spree_cm_commissioner/multi_leg_trips_query.rb +7 -0
  163. data/app/queries/spree_cm_commissioner/pie_chart_event_aggregator_queries.rb +3 -2
  164. data/app/queries/spree_cm_commissioner/single_leg_trips_query.rb +2 -1
  165. data/app/queries/spree_cm_commissioner/user_votes_per_contestant_query.rb +48 -0
  166. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +2 -2
  167. data/app/serializers/spree/v2/storefront/product_serializer_decorator.rb +4 -0
  168. data/app/serializers/spree/v2/storefront/taxon_serializer_decorator.rb +3 -0
  169. data/app/serializers/spree/v2/storefront/user_serializer_decorator.rb +5 -2
  170. data/app/serializers/spree/v2/storefront/variant_serializer_decorator.rb +2 -1
  171. data/app/serializers/spree/v2/tenant/guest_serializer.rb +2 -1
  172. data/app/serializers/spree/v2/tenant/my_vote_serializer.rb +19 -0
  173. data/app/serializers/spree/v2/tenant/product_serializer.rb +5 -0
  174. data/app/serializers/spree/v2/tenant/saved_guest_serializer.rb +23 -0
  175. data/app/serializers/spree/v2/tenant/show_episode_serializer.rb +1 -9
  176. data/app/serializers/spree/v2/tenant/show_serializer.rb +2 -1
  177. data/app/serializers/spree/v2/tenant/user_serializer.rb +1 -1
  178. data/app/serializers/spree/v2/tenant/variant_serializer.rb +2 -1
  179. data/app/serializers/spree/v2/tenant/voting_contestant_serializer.rb +2 -0
  180. data/app/serializers/spree_cm_commissioner/v2/storefront/cart_serializer_decorator.rb +1 -0
  181. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_serializer.rb +3 -6
  182. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_serializer.rb +2 -2
  183. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_result_serializer.rb +2 -2
  184. data/app/serializers/spree_cm_commissioner/v2/storefront/trip_serializer.rb +3 -1
  185. data/app/services/spree_cm_commissioner/api_caches/invalidate.rb +24 -3
  186. data/app/services/spree_cm_commissioner/cart/add_guest.rb +30 -3
  187. data/app/services/spree_cm_commissioner/cart/add_item_decorator.rb +22 -0
  188. data/app/services/spree_cm_commissioner/cart/empty_decorator.rb +23 -0
  189. data/app/services/spree_cm_commissioner/cart/remove_guest.rb +26 -1
  190. data/app/services/spree_cm_commissioner/cart/remove_item_decorator.rb +17 -0
  191. data/app/services/spree_cm_commissioner/cart/remove_line_item_decorator.rb +17 -0
  192. data/app/services/spree_cm_commissioner/cart/set_quantity_decorator.rb +17 -0
  193. data/app/services/spree_cm_commissioner/check_ins/create_bulk.rb +10 -6
  194. data/app/services/spree_cm_commissioner/draft_order/create.rb +95 -0
  195. data/app/services/spree_cm_commissioner/fraud_check.rb +9 -0
  196. data/app/services/spree_cm_commissioner/guests/create.rb +82 -0
  197. data/app/services/spree_cm_commissioner/guests/refresh_data_fill_stage.rb +20 -0
  198. data/app/services/spree_cm_commissioner/guests/send_dynamic_field_notification.rb +15 -0
  199. data/app/services/spree_cm_commissioner/guests/update.rb +68 -0
  200. data/app/services/spree_cm_commissioner/imports/contestants/create.rb +19 -1
  201. data/app/services/spree_cm_commissioner/imports/orders/cancel.rb +63 -0
  202. data/app/services/spree_cm_commissioner/imports/orders/create.rb +1 -0
  203. data/app/services/spree_cm_commissioner/inventory_holds/release.rb +18 -0
  204. data/app/services/spree_cm_commissioner/inventory_holds/validate_limits.rb +8 -3
  205. data/app/services/spree_cm_commissioner/line_items/validate_purchase_limits.rb +97 -0
  206. data/app/services/spree_cm_commissioner/load_test/create_accounts.rb +68 -0
  207. data/app/services/spree_cm_commissioner/load_test/destroy_accounts.rb +47 -0
  208. data/app/services/spree_cm_commissioner/load_test/flow_registry.rb +26 -0
  209. data/app/services/spree_cm_commissioner/load_test/generate_booking_ticket_data.rb +204 -0
  210. data/app/services/spree_cm_commissioner/load_test/generate_voting_fixture_data.rb +178 -0
  211. data/app/services/spree_cm_commissioner/load_test/login_token.rb +46 -0
  212. data/app/services/spree_cm_commissioner/operator_guest_json_gzips/create.rb +14 -7
  213. data/app/services/spree_cm_commissioner/order/guests/update.rb +53 -0
  214. data/app/services/spree_cm_commissioner/organizer/export_guest_csv_service.rb +12 -11
  215. data/app/services/spree_cm_commissioner/pricing_models/create_with_rule_groups.rb +9 -3
  216. data/app/services/spree_cm_commissioner/pricing_models/preview.rb +49 -6
  217. data/app/services/spree_cm_commissioner/pricing_models/update_with_rule_groups.rb +10 -7
  218. data/app/services/spree_cm_commissioner/show_contestants/normalize_video_highlights.rb +5 -1
  219. data/app/services/spree_cm_commissioner/telegram_alerts/checks/order_complete_payment_not_paid.rb +21 -0
  220. data/app/services/spree_cm_commissioner/telegram_alerts/checks/payment_paid_order_not_complete.rb +21 -0
  221. data/app/services/spree_cm_commissioner/telegram_alerts/order_integrity_alert.rb +112 -0
  222. data/app/services/spree_cm_commissioner/telegram_alerts/order_integrity_checks_runner.rb +32 -0
  223. data/app/services/spree_cm_commissioner/trips/update_single_leg.rb +6 -1
  224. data/app/services/spree_cm_commissioner/user_authenticator.rb +22 -1
  225. data/app/services/spree_cm_commissioner/voting_contestants/advancer.rb +10 -3
  226. data/app/services/spree_cm_commissioner/voting_contestants/assigner.rb +20 -2
  227. data/app/services/spree_cm_commissioner/voting_contestants/bulk_updater.rb +15 -9
  228. data/app/services/spree_cm_commissioner/voting_credits/allocate.rb +13 -2
  229. data/app/services/spree_cm_commissioner/voting_leaderboards/time_range_result.rb +79 -0
  230. data/app/services/spree_cm_commissioner/waiting_room/publish_lobby_path.rb +57 -0
  231. data/app/services/spree_cm_commissioner/waiting_room/stamp_queue_positions.rb +185 -0
  232. data/app/services/spree_cm_commissioner/waiting_room_lobby_metadata_fetcher.rb +47 -0
  233. data/app/services/spree_cm_commissioner/waiting_room_system_metadata_fetcher.rb +19 -5
  234. data/app/services/spree_cm_commissioner/waiting_room_system_metadata_setter.rb +28 -5
  235. data/app/views/spree/admin/featured_trips/index.html.erb +1 -1
  236. data/app/views/spree/admin/guests/_form.html.erb +37 -0
  237. data/app/views/spree/admin/import_new_orders/_cancel_modal.html.erb +35 -0
  238. data/app/views/spree/admin/import_new_orders/index.html.erb +4 -0
  239. data/app/views/spree/admin/import_new_orders/show.html.erb +30 -0
  240. data/app/views/spree/admin/imports/index.html.erb +2 -0
  241. data/app/views/spree/admin/inventory_holds/index.html.erb +8 -3
  242. data/app/views/spree/admin/shared/_system_tabs.html.erb +14 -0
  243. data/app/views/spree/admin/system/load_test_accounts/_login_tokens_modal.html.erb +52 -0
  244. data/app/views/spree/admin/system/load_test_accounts/index.html.erb +175 -0
  245. data/app/views/spree/admin/system/load_test_flows/index.html.erb +66 -0
  246. data/app/views/spree/admin/system/load_testing/index.html.erb +25 -0
  247. data/app/views/spree/admin/system/maintenance_tasks/_search.html.erb +28 -0
  248. data/app/views/spree/admin/system/maintenance_tasks/index.html.erb +71 -0
  249. data/app/views/spree/admin/system/waiting_room/show.html.erb +58 -0
  250. data/app/views/spree/admin/tenants/_form.html.erb +40 -1
  251. data/app/views/spree/admin/tenants/form/_telegram_auth.html.erb +61 -0
  252. data/app/views/spree/admin/variants/fixture.html.erb +49 -0
  253. data/app/views/spree/order_mailer/confirm_email.html.erb +10 -0
  254. data/app/views/spree_cm_commissioner/order_mailer/_mailer_stylesheets.html.erb +12 -0
  255. data/app/views/spree_cm_commissioner/order_mailer/purchased_items/_items.html.erb +12 -9
  256. data/config/initializers/doorkeeper.rb +10 -6
  257. data/config/initializers/spree_permitted_attributes.rb +57 -0
  258. data/config/load_test_flows/platform.yml +25 -0
  259. data/config/load_test_flows/tenant.yml +93 -0
  260. data/config/locales/en.yml +147 -17
  261. data/config/locales/km.yml +51 -12
  262. data/config/routes.rb +36 -1
  263. data/db/migrate/20260616000001_add_canceled_by_id_to_cm_imports.rb +5 -0
  264. data/db/migrate/20260617000002_create_cm_imported_orders.rb +12 -0
  265. data/db/migrate/20260619000001_create_cm_idempotency_keys.rb +11 -0
  266. data/db/migrate/20260629000001_add_term_of_use_to_spree_vendors.rb +5 -0
  267. data/db/migrate/20260630000001_add_trip_to_cm_pricing_model_routes.rb +7 -0
  268. data/db/migrate/20260701000001_add_device_info_to_cm_waiting_room_sessions.rb +14 -0
  269. data/db/migrate/20260703065239_add_position_to_cm_voting_contestants.rb +6 -0
  270. data/db/migrate/20260708150000_add_name_and_short_name_to_cm_trips.rb +6 -0
  271. data/db/migrate/20260713022227_add_advanced_to_episode_id_to_cm_voting_contestants.rb +8 -0
  272. data/db/migrate/20260714002626_rename_data_fill_stage_phase_on_cm_guests.rb +5 -0
  273. data/db/migrate/20260720000001_add_check_in_fields_to_spree_roles.rb +11 -0
  274. data/db/migrate/20260723000000_add_payment_host_to_cm_tenants.rb +6 -0
  275. data/db/migrate/20260723000001_add_metadata_to_spree_roles.rb +11 -0
  276. data/db/migrate/20260728074153_add_role_to_cm_exports.rb +5 -0
  277. data/db/migrate/20260729000000_add_visibility_to_cm_trips.rb +6 -0
  278. data/db/migrate/20260729000001_add_session_created_at_index_to_cm_votes.rb +12 -0
  279. data/db/migrate/20260730000000_add_purchase_limit_scopes_to_spree_orders.rb +22 -0
  280. data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +0 -6
  281. data/lib/spree_cm_commissioner/test_helper/factories/pricing_model_trip_factory.rb +11 -0
  282. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
  283. data/lib/spree_cm_commissioner/trip_result.rb +3 -1
  284. data/lib/spree_cm_commissioner/version.rb +1 -1
  285. data/lib/tasks/recompute_guest_data_fill_stage.rake +19 -0
  286. metadata +118 -13
  287. data/app/controllers/spree/api/v2/storefront/saved_guests_controller.rb +0 -77
  288. data/app/interactors/spree_cm_commissioner/guest_dynamic_field_notification_sender.rb +0 -11
  289. data/app/interactors/spree_cm_commissioner/guest_dynamic_fields_manager.rb +0 -33
  290. data/app/serializers/spree/v2/storefront/order_serializer_decorator.rb +0 -63
  291. data/app/serializers/spree_cm_commissioner/v2/storefront/guest_minimal_serializer.rb +0 -30
  292. data/app/serializers/spree_cm_commissioner/v2/storefront/line_item_minimal_serializer.rb +0 -57
  293. data/app/serializers/spree_cm_commissioner/v2/storefront/ticket_transfer_minimal_serializer.rb +0 -17
  294. data/app/services/spree_cm_commissioner/update_guest_service.rb +0 -129
  295. data/app/services/spree_cm_commissioner/users/incomplete_guest_checker_service.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f0d6bc194265bc170fa7f5d480c4c3aead23d86827c1f80896237f8c3864d6c
4
- data.tar.gz: 7fb03f4121f2cdead7cbb774489c675663dc172bb62c9b6c3a7b06c67c52c08a
3
+ metadata.gz: ca0138759a1da40541b5d076fb9709847d44d88885593f5b69921993cfd26591
4
+ data.tar.gz: 79408535d56a9d4b62cac5154a316f6652d6d8664c04a030f00588b39f7ddd24
5
5
  SHA512:
6
- metadata.gz: cb11254307ddad72b7941b7474ee8fc473474dac0abfaa95a3d6eb15c803fe86a7bafb60b8705d40a93c00e83d39836846ed6ed16bf45453e47301f5666ce058
7
- data.tar.gz: 1880e96a3b09bc6fb3efcc72649221b0603ab1a87d1774dd13badf47ba38f57d94b875a9261f369ab839ada7c35d698ffe4230c1d6b327654ecec693e74cc41d
6
+ metadata.gz: 3e1a90b2f9115755fcd8cb777e0cd4d3c05b950a8a1b913ac526be4c5967d062533b5683bf48d3ca979e726347bb1945520b0701337872e7626d2fc3524d7952
7
+ data.tar.gz: 8b4813fe21cc8495e2a512ea1662e2105ba61994c1866794bd9da91ef5c805b1b49cc9d8ea5cdf53f35dd2fe6a96295491eea72853cfdaf899377264922e8a84
data/.env.example CHANGED
@@ -20,11 +20,22 @@ WAITING_ROOM_SESSION_SIGNATURE="e6b2********************26e3"
20
20
  WAITING_ROOM_SESSION_EXPIRE_DURATION_IN_SECOND=
21
21
  WAITING_ROOM_MIN_SESSIONS_COUNT=5
22
22
  WAITING_ROOM_DISABLED=no
23
+ WAITING_ROOM_POSITION_STAMP_LIMIT=1000
24
+ WAITING_ROOM_FIRESTORE_BATCH_SIZE=500
25
+ WAITING_ROOM_MIN_WAIT_TO_ENTER_SECONDS=600 # Waiting Room step floor (10 min)
26
+ WAITING_ROOM_MIN_QUEUE_TO_ENTER_SECONDS=300 # Queue step floor (5 min)
27
+ WAITING_ROOM_MAX_WAIT_TO_DISPLAY_SECONDS=3600 # above this the ETA is hidden (1 h)
28
+ WAITING_ROOM_CALLER_INTERVAL_SECONDS=60 # how often the caller runs; match the waiting_guests_caller cron
29
+ WAITING_ROOM_MAX_ETA_BATCH_SIZE=50 # cap on batch size assumed when estimating the ETA
23
30
 
24
31
  # Vattanac Bank
25
32
  VATTANAC_AES_SECRET_KEY= ""
26
33
  VATTANAC_PUBLIC_KEY=""
27
34
 
35
+ # Telegram OAuth (OpenID Connect) login client_id/client_secret are configured
36
+ # per tenant (or on the default store for tenant-less logins) from the admin
37
+ # under Telegram Authentication - see docs/authentication/telegram-login.md.
38
+
28
39
  # Organizer URL
29
40
  ORGANIZER_URL=http://127.0.0.1:4000/organizer
30
41
 
@@ -45,6 +56,9 @@ CACHE_DEFAULT_MAX_AGE=300 # Default for unlisted controllers - 5 minutes
45
56
  # Batch size for processing maintenance tasks in app/jobs/spree_cm_commissioner/maintenance_tasks/orchestrate_job.rb
46
57
  MAINTENANCE_TASKS_BATCH_SIZE=100
47
58
 
59
+ # Batch size for slicing guest_ids when enqueuing RefinalizeGuestsBatchJob in app/models/spree_cm_commissioner/maintenance_tasks/event.rb
60
+ MAINTENANCE_TASKS_REFINALIZE_GUESTS_BATCH_SIZE=300
61
+
48
62
  # Export related:
49
63
  OPERATOR_GUEST_JSON_GZIP_CACHE_HOURS=24
50
64
  EXPORT_PRESIGNED_URL_EXPIRATION_MINUTES=15
@@ -63,3 +77,9 @@ PAYMENT_LOCK_MIN_DURATION_IN_MINUTES=5 # Minimum remaining hold time requir
63
77
  MAX_ACTIVE_HOLDS_PER_USER=3 # Max concurrent active holds allowed per user across all orders
64
78
  MAX_HOLDS_PER_IP_PER_HOUR=5 # Max hold attempts per IP address within a rolling 1-hour window (abuse prevention)
65
79
  HOLD_COOLDOWN_AFTER_EXPIRY_IN_MINUTES=2 # Cooldown period before a user can re-acquire a hold after one expired on them
80
+
81
+ # See: app/models/spree_cm_commissioner/payment_decorator.rb
82
+ PAYMENT_INCOMPLETE_NOTIFICATION_DELAY_IN_MINUTES=5 # Delay before notifying a customer that their order is still unpaid after payment is created
83
+
84
+ # See: app/jobs/spree_cm_commissioner/telegram_alerts/order_integrity_check_job.rb
85
+ ORDER_INTEGRITY_TELEGRAM_ALERT_ENABLED="no" # Set to yes to enable the order integrity Telegram alert job (off by default to avoid flooding Telegram rate limits during traffic spikes)
@@ -163,8 +163,9 @@ jobs:
163
163
  - name: Security
164
164
  env:
165
165
  DATABASE_URL: postgres://myuser:mypassword@localhost:5432/test_db
166
+
167
+ # Using --no-threads to bypass a known Ruby 3.2.0 GC segmentation fault in CI.
166
168
  run: |
167
- # Using --no-threads to bypass a known Ruby 3.2.0 GC segmentation fault in CI.
168
169
  bundle exec brakeman --no-threads --no-exit-on-warn
169
170
 
170
171
  test:
data/Gemfile.lock CHANGED
@@ -34,7 +34,7 @@ GIT
34
34
  PATH
35
35
  remote: .
36
36
  specs:
37
- spree_cm_commissioner (2.8.15.pre.pre8)
37
+ spree_cm_commissioner (2.8.15)
38
38
  activerecord-multi-tenant
39
39
  activerecord_json_validator (~> 2.1, >= 2.1.3)
40
40
  aws-sdk-cloudfront
@@ -886,7 +886,7 @@ GEM
886
886
  spree_backend (>= 4.3.0.rc1)
887
887
  spree_emails (>= 4.3.0.rc1)
888
888
  spree_extension
889
- spree_vpago (2.0.5.pre.beta)
889
+ spree_vpago (2.3.4)
890
890
  faraday
891
891
  google-cloud-firestore
892
892
  spree_api (>= 4.5)
@@ -27,6 +27,13 @@ module SpreeCmCommissioner
27
27
  PopularRoutesController
28
28
  RoutePlacesController
29
29
  ShowsController
30
+ EpisodesController
31
+ ShowPeopleController
32
+ ShowPersonAssignmentsController
33
+ ShowContestantsController
34
+ VotePackagesController
35
+ ShowEliminationSessionsController
36
+ PaymentMethodsController
30
37
  ].freeze
31
38
 
32
39
  # Priority 3: Moderate Freshness (30 minutes)
@@ -46,6 +53,7 @@ module SpreeCmCommissioner
46
53
  HIGH_FRESHNESS_CONTROLLERS = %w[
47
54
  TripsController
48
55
  TripSearchController
56
+ VotingContestantsController
49
57
  ].freeze
50
58
 
51
59
  def shared_max_age
@@ -0,0 +1,80 @@
1
+ module SpreeCmCommissioner
2
+ module LoadTestAccountManagement
3
+ extend ActiveSupport::Concern
4
+
5
+ include SpreeCmCommissioner::LoadTestAccountScope
6
+
7
+ included do
8
+ before_action :authorize_load_testing!, only: %i[create bulk_destroy]
9
+ end
10
+
11
+ # Ensures N load-test accounts exist (idempotent) for `load_test_tenant` (nil = platform).
12
+ def create
13
+ result = SpreeCmCommissioner::LoadTest::CreateAccounts.call(**pool_params)
14
+
15
+ if result.success?
16
+ flash[:success] = "#{result.value[:created]} load-test accounts created."
17
+ else
18
+ flash[:error] = result.error.value
19
+ end
20
+
21
+ redirect_to manage_accounts_redirect_path
22
+ rescue StandardError => e
23
+ flash[:error] = e.message
24
+ redirect_to manage_accounts_redirect_path
25
+ end
26
+
27
+ def bulk_destroy
28
+ result = SpreeCmCommissioner::LoadTest::DestroyAccounts.call(**pool_params)
29
+
30
+ if result.success?
31
+ flash[:success] = "#{result.value[:destroyed]} destroyed, #{result.value[:not_found]} not found (already removed)."
32
+ else
33
+ flash[:error] = result.error.value
34
+ end
35
+
36
+ redirect_to manage_accounts_redirect_path
37
+ rescue StandardError => e
38
+ flash[:error] = e.message
39
+ redirect_to manage_accounts_redirect_path
40
+ end
41
+
42
+ private
43
+
44
+ # Default: cancancan's `authorize!`. Override in the including controller if it doesn't use
45
+ # cancancan (e.g. the organizer dashboard, which authorizes via RoleAuthorization/can_manage?).
46
+ def authorize_load_testing!
47
+ authorize! :manage, :load_testing
48
+ end
49
+
50
+ # Where create/bulk_destroy redirect back to. Must be implemented by the including controller
51
+ # (points at its own Load Test Accounts page).
52
+ def manage_accounts_redirect_path
53
+ raise NotImplementedError, "#{self.class} must implement #manage_accounts_redirect_path"
54
+ end
55
+
56
+ def pool_params
57
+ {
58
+ client_id: resolve_client_id,
59
+ count: params[:count].presence&.to_i || 20,
60
+ email_prefix: params[:email_prefix].presence || 'loadtest',
61
+ email_domain: params[:email_domain].presence
62
+ }
63
+ end
64
+
65
+ # Carries the form field values through the redirect so the index page re-renders with the
66
+ # same count/prefix/domain/page/per_page the admin/organizer just submitted with.
67
+ def redirect_params
68
+ params.slice(:count, :email_prefix, :email_domain, :page, :per_page).permit!
69
+ end
70
+
71
+ def resolve_client_id
72
+ return nil if load_test_tenant.nil?
73
+
74
+ application = Spree::OauthApplication.where(tenant_id: load_test_tenant.id).order(:id).first
75
+ raise "No OAuth application found for tenant #{load_test_tenant.name}" unless application
76
+
77
+ application.uid
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,39 @@
1
+ module SpreeCmCommissioner
2
+ module LoadTestAccountScope
3
+ extend ActiveSupport::Concern
4
+
5
+ private
6
+
7
+ # The tenant these accounts are scoped to. nil means the platform (no tenant). Must be
8
+ # implemented by the including controller.
9
+ def load_test_tenant
10
+ raise NotImplementedError, "#{self.class} must implement #load_test_tenant"
11
+ end
12
+
13
+ DEFAULT_EXPORT_PER_PAGE = 10
14
+
15
+ # Queried fresh from the DB every time, so it's always in sync with the current pool rather than
16
+ # a stashed file or session state.
17
+ #
18
+ # Filters the `load_test_account` flag in SQL via the model's `load_test_accounts` scope (see
19
+ # UserDecorator), so only the tenant's load-test accounts are considered — never the whole users
20
+ # table. Unlike the old `order(:id).limit(2000).select(&:...)` approach, there's no scan cap:
21
+ # newly created accounts (highest ids, ordered first below) always show up even on tenants with
22
+ # far more than 2,000 users.
23
+ #
24
+ # Kaminari pages on the relation itself, so the DB only ever loads the current page's rows
25
+ # (`LIMIT`/`OFFSET`) — never the full pool into memory — via the same `page`/`per_page` params
26
+ # and `paginate` view helper every other index page in this app uses.
27
+ #
28
+ # Shared between LoadTestAccountManagement (lists/mutates the pool) and
29
+ # LoadTestLoginTokenGeneration (mints tokens for exactly the page shown), so both controllers
30
+ # resolve the same page the same way.
31
+ def export_accounts
32
+ Spree::User.where(tenant_id: load_test_tenant&.id)
33
+ .load_test_accounts
34
+ .order(id: :desc)
35
+ .page(params[:page])
36
+ .per(params[:per_page] || DEFAULT_EXPORT_PER_PAGE)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ module SpreeCmCommissioner
2
+ # Sets Current.load_test_bypass when the request carries the correct X-Request-Verify secret, so
3
+ # anti-abuse services (e.g. InventoryHolds::ValidateLimits) can skip their checks for trusted
4
+ # load tests. No-op unless LOAD_TEST_BYPASS_KEY is set. Include in any controller that can
5
+ # trigger such a check.
6
+ module LoadTestBypassable
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ before_action :set_load_test_bypass_current
11
+ end
12
+
13
+ private
14
+
15
+ # Always assigns the flag (false unless the request carries the correct
16
+ # secret), so its value never leaks from a previous request.
17
+ def set_load_test_bypass_current
18
+ SpreeCmCommissioner::Current.load_test_bypass = load_test_bypass_requested?
19
+ end
20
+
21
+ def load_test_bypass_requested?
22
+ key = ENV.fetch('LOAD_TEST_BYPASS_KEY', nil)
23
+ return false if key.blank?
24
+
25
+ provided = request.headers.fetch('X-Request-Verify', nil).to_s
26
+ ActiveSupport::SecurityUtils.secure_compare(provided, key)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ module SpreeCmCommissioner
2
+ module LoadTestLoginTokenGeneration
3
+ extend ActiveSupport::Concern
4
+
5
+ include SpreeCmCommissioner::LoadTestAccountScope
6
+
7
+ included do
8
+ before_action :authorize_load_testing!, only: %i[create]
9
+ end
10
+
11
+ # Mints a fresh, stateless login-token JWT for each account on the requested page (same
12
+ # page/per_page as the Load Test Accounts index) and returns them as JSON. Nothing is
13
+ # persisted — the tokens are self-contained and verified by signature + expiry alone (see
14
+ # SpreeCmCommissioner::LoadTest::LoginToken).
15
+ def create
16
+ render json: login_tokens_payload(export_accounts)
17
+ rescue StandardError => e
18
+ render json: { error: e.message }, status: :unprocessable_entity
19
+ end
20
+
21
+ private
22
+
23
+ # Default: cancancan's `authorize!`. Override in the including controller if it doesn't use
24
+ # cancancan (e.g. the organizer dashboard, which authorizes via RoleAuthorization/can_manage?).
25
+ def authorize_load_testing!
26
+ authorize! :manage, :load_testing
27
+ end
28
+
29
+ # aud claim: the admin/organizer who minted the tokens. No fallback — both hosting controllers
30
+ # already require an authenticated user for every action here, so spree_current_user being
31
+ # absent would be a bug worth raising on, not silently mislabeling as 'system'.
32
+ def token_audience
33
+ spree_current_user.id
34
+ end
35
+
36
+ # user_id + the user_id_token are all k6 needs (email and expiry are already claims inside the
37
+ # JWT itself — sub / exp — and the token alone identifies + authenticates the account via
38
+ # UserPasswordAuthenticator's token-only path). expires_at is included too, purely so the
39
+ # generated-tokens list can show it to a human without decoding the JWT. Named `user_id_token`
40
+ # (not `id_token`) so UserAuthenticator can route on the params key alone, without decoding
41
+ # every request's `id_token` to check whether it's a load-test token.
42
+ def login_tokens_payload(accounts)
43
+ accounts.map do |user|
44
+ generated = SpreeCmCommissioner::LoadTest::LoginToken.generate(user: user, audience: token_audience)
45
+ {
46
+ user_id: user.id,
47
+ user_id_token: generated[:token],
48
+ expires_at: generated[:expires_at]
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -12,6 +12,7 @@ module SpreeCmCommissioner
12
12
  end
13
13
 
14
14
  @spree_current_order.last_ip_address = request.remote_ip
15
+ @spree_current_order.device_id = device_id if device_id.present?
15
16
  @spree_current_order
16
17
  end
17
18
 
@@ -25,5 +26,9 @@ module SpreeCmCommissioner
25
26
  state: params[:state]
26
27
  )
27
28
  end
29
+
30
+ def device_id
31
+ params[:device_id].presence
32
+ end
28
33
  end
29
34
  end
@@ -27,13 +27,15 @@ module SpreeCmCommissioner
27
27
  return unless result.failure?
28
28
 
29
29
  render json: {
30
- errors: [{
31
- status: '403',
32
- error_code: 'human_verification_failed',
33
- title: I18n.t('turnstile.verification_failed'),
34
- detail: result.message
35
- }
36
- ]
30
+ errors: [
31
+ {
32
+ status: '403',
33
+ error_code: 'human_verification_failed',
34
+ title: I18n.t('turnstile.verification_failed'),
35
+ detail: result.message,
36
+ turnstile_error_code: result.respond_to?(:error_code) ? result.error_code : nil
37
+ }
38
+ ]
37
39
  }, status: :forbidden
38
40
  end
39
41
 
@@ -80,8 +80,10 @@ module Spree
80
80
 
81
81
  def permitted_resource_params
82
82
  params.require(object_name).permit(:first_name, :last_name, :gender, :dob, :occupation_id,
83
- :nationality_id, :age, :emergency_contact, :line_item_id,
84
- :seat_number, :phone_number
83
+ :nationality_id, :age, :emergency_contact,
84
+ :line_item_id, :seat_number, :phone_number, :contact,
85
+ :other_organization, :expectation, :address,
86
+ :social_contact_platform, :social_contact
85
87
  )
86
88
  end
87
89
 
@@ -23,6 +23,31 @@ module Spree
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ # POST: /admin/orders/import_new_orders/:id/cancel
28
+ def cancel
29
+ import = model_class.find(params[:id])
30
+ show_url = spree.admin_import_new_order_url(import.id)
31
+
32
+ unless import.cancellable?
33
+ flash[:error] = 'These orders cannot be canceled.' # rubocop:disable Rails/I18nLocaleTexts
34
+ redirect_to show_url and return
35
+ end
36
+
37
+ if params[:confirm_name].to_s.strip != import.name.to_s.strip
38
+ flash[:error] = 'Import name did not match. Cancellation aborted.' # rubocop:disable Rails/I18nLocaleTexts
39
+ redirect_to show_url and return
40
+ end
41
+
42
+ SpreeCmCommissioner::CancelImportOrderJob.perform_later(
43
+ import_order_id: import.id,
44
+ canceled_by_user_id: spree_current_user.id,
45
+ cancellation_reason: params[:cancellation_reason].to_s.strip.presence
46
+ )
47
+
48
+ flash[:success] = "Canceling orders from \"#{import.name}\". This runs in the background."
49
+ redirect_to show_url
50
+ end
26
51
  end
27
52
  end
28
53
  end
@@ -9,6 +9,7 @@ module Spree
9
9
  q['s'] ||= 'created_at desc'
10
10
  q['created_at_gt'] = parse_time_or_nil(q['created_at_gt'], :beginning_of_day) if q['created_at_gt'].present?
11
11
  q['created_at_lt'] = parse_time_or_nil(q['created_at_lt'], :end_of_day) if q['created_at_lt'].present?
12
+ normalize_enum_filters!(q)
12
13
 
13
14
  @search = scope.ransack(q)
14
15
  result_scope = @search.result(distinct: true)
@@ -18,7 +19,11 @@ module Spree
18
19
  .page(params[:page])
19
20
  .per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
20
21
 
21
- @status_counts = result_scope.reorder(nil).group(:status).count
22
+ # Status tab counts must reflect every other filter but NOT the status filter, so
23
+ # each tab shows how many holds it would return (otherwise selecting one status
24
+ # zeroes out all the other tabs).
25
+ @status_counts = scope.ransack(q.except('status_eq')).result(distinct: true)
26
+ .reorder(nil).group(:status).count
22
27
  end
23
28
 
24
29
  def release
@@ -44,8 +49,23 @@ module Spree
44
49
 
45
50
  private
46
51
 
52
+ # `status` and `release_reason` are integer-backed enums. Ransack casts a string
53
+ # value for an integer column with String#to_i, so "payment_locked" becomes 0
54
+ # (== :pending) and every label silently filters to the wrong status. Translate
55
+ # enum labels to their stored integer before searching.
56
+ def normalize_enum_filters!(query)
57
+ {
58
+ 'status_eq' => SpreeCmCommissioner::InventoryHold.statuses,
59
+ 'release_reason_eq' => SpreeCmCommissioner::InventoryHold.release_reasons
60
+ }.each do |key, mapping|
61
+ value = query[key]
62
+ query[key] = mapping[value.to_s] if value.present? && mapping.key?(value.to_s)
63
+ end
64
+ end
65
+
47
66
  def back_params
48
67
  raw_params = params[:back_params].presence || params
68
+ raw_params = raw_params.to_unsafe_h if raw_params.respond_to?(:to_unsafe_h)
49
69
  ActionController::Parameters.new(raw_params).permit(:page, :per_page, q: {})
50
70
  end
51
71
 
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class LoadTestAccountsController < Spree::Admin::BaseController
5
+ include SpreeCmCommissioner::LoadTestAccountManagement
6
+
7
+ def index
8
+ @export_accounts = export_accounts
9
+ end
10
+
11
+ private
12
+
13
+ # nil = platform. Admin load testing never operates on a tenant.
14
+ def load_test_tenant
15
+ nil
16
+ end
17
+
18
+ def manage_accounts_redirect_path
19
+ admin_system_load_test_accounts_path(**redirect_params)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class LoadTestFlowsController < Spree::Admin::BaseController
5
+ def index
6
+ @load_test_flows = SpreeCmCommissioner::LoadTest::FlowRegistry.for_workflow('platform')
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class LoadTestLoginTokensController < Spree::Admin::BaseController
5
+ include SpreeCmCommissioner::LoadTestLoginTokenGeneration
6
+
7
+ private
8
+
9
+ # nil = platform. Admin load testing never operates on a tenant.
10
+ def load_test_tenant
11
+ nil
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class LoadTestingController < Spree::Admin::BaseController
5
+ def index; end
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,64 @@
1
+ module Spree
2
+ module Admin
3
+ module System
4
+ class MaintenanceTasksController < Spree::Admin::BaseController
5
+ def index
6
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
7
+
8
+ @search = scope.ransack(params[:q])
9
+ @tasks = @search.result(distinct: true)
10
+ .order(created_at: :desc)
11
+ .page(params[:page])
12
+ .per(params[:per_page] || Spree::Backend::Config[:admin_orders_per_page])
13
+ end
14
+
15
+ def run_now
16
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
17
+
18
+ task = SpreeCmCommissioner::MaintenanceTask.find(params[:id])
19
+
20
+ if task.completed_at.present?
21
+ flash[:error] = "Task ##{task.id} is already completed."
22
+ else
23
+ task.update!(manually_triggered: true)
24
+ task.execute
25
+
26
+ if task.completed_at.present?
27
+ flash[:success] = "Task ##{task.id} (#{task.type.demodulize}) ran successfully."
28
+ else
29
+ flash[:error] = "Task ##{task.id} (#{task.type.demodulize}) failed: #{task.last_error}"
30
+ end
31
+ end
32
+
33
+ redirect_to admin_system_maintenance_tasks_path(back_params)
34
+ end
35
+
36
+ def destroy
37
+ authorize! :manage, SpreeCmCommissioner::MaintenanceTask
38
+
39
+ task = SpreeCmCommissioner::MaintenanceTask.find(params[:id])
40
+
41
+ if task.destroy
42
+ flash[:success] = "Task ##{task.id} has been deleted."
43
+ else
44
+ flash[:error] = task.errors.full_messages.to_sentence.presence || "Failed to delete task ##{task.id}."
45
+ end
46
+
47
+ redirect_to admin_system_maintenance_tasks_path(back_params)
48
+ end
49
+
50
+ private
51
+
52
+ def scope
53
+ SpreeCmCommissioner::MaintenanceTask.accessible_by(current_ability, :manage)
54
+ end
55
+
56
+ def back_params
57
+ raw_params = params[:back_params].presence || params
58
+ raw_params = raw_params.to_unsafe_h if raw_params.respond_to?(:to_unsafe_h)
59
+ ActionController::Parameters.new(raw_params).permit(:page, :per_page, q: {})
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -4,7 +4,10 @@ module Spree
4
4
  class WaitingRoomController < Spree::Admin::BaseController
5
5
  def show
6
6
  @fetcher = SpreeCmCommissioner::WaitingRoomSystemMetadataFetcher.new
7
+ @lobby_fetcher = SpreeCmCommissioner::WaitingRoomLobbyMetadataFetcher.new
8
+
7
9
  @fetcher.load_document_data
10
+ @lobby_fetcher.load_document_data
8
11
 
9
12
  @active_sesions_count = SpreeCmCommissioner::WaitingRoomSession.active.count
10
13
  end
@@ -23,12 +26,31 @@ module Spree
23
26
  redirect_back fallback_location: admin_system_waiting_room_path
24
27
  end
25
28
 
29
+ def modify_max_sessions_count_cap
30
+ modifier = params[:max_sessions_count_cap]&.to_i || 0
31
+ SpreeCmCommissioner::WaitingRoomSystemMetadataSetter.new.modify_max_sessions_count_cap(modifier)
32
+
33
+ redirect_back fallback_location: admin_system_waiting_room_path
34
+ end
35
+
26
36
  def force_pull
27
37
  SpreeCmCommissioner::WaitingRoomLatestSystemMetadataPullerJob.perform_now
28
38
  SpreeCmCommissioner::WaitingGuestsCallerJob.perform_now
29
39
 
30
40
  redirect_back fallback_location: admin_system_waiting_room_path
31
41
  end
42
+
43
+ def publish_lobby_path
44
+ result = SpreeCmCommissioner::WaitingRoom::PublishLobbyPath.call
45
+
46
+ if result.success?
47
+ flash[:success] = "Published waiting guests records path: #{result.value[:records_path]}"
48
+ else
49
+ flash[:error] = result.error.to_s
50
+ end
51
+
52
+ redirect_back fallback_location: admin_system_waiting_room_path
53
+ end
32
54
  end
33
55
  end
34
56
  end
@@ -28,6 +28,10 @@ module Spree
28
28
  remove_asset(@taxon.home_banner)
29
29
  end
30
30
 
31
+ def remove_ad_banner
32
+ remove_asset(@taxon.ad_banner)
33
+ end
34
+
31
35
  def remove_video_banner
32
36
  remove_asset(@taxon.video_banner)
33
37
  end
@@ -49,6 +53,7 @@ module Spree
49
53
  @taxon.build_app_banner(attachment: permitted_resource_params.delete(:app_banner)) if permitted_resource_params[:app_banner]
50
54
  @taxon.build_web_banner(attachment: permitted_resource_params.delete(:web_banner)) if permitted_resource_params[:web_banner]
51
55
  @taxon.build_home_banner(attachment: permitted_resource_params.delete(:home_banner)) if permitted_resource_params[:home_banner]
56
+ @taxon.build_ad_banner(attachment: permitted_resource_params.delete(:ad_banner)) if permitted_resource_params[:ad_banner]
52
57
  @taxon.build_video_banner(attachment: permitted_resource_params.delete(:video_banner)) if permitted_resource_params[:video_banner]
53
58
  end
54
59
 
@@ -20,8 +20,26 @@ module Spree
20
20
  end
21
21
  end
22
22
 
23
+ # override
24
+ def update
25
+ preserve_non_form_roles
26
+ super
27
+ end
28
+
23
29
  private
24
30
 
31
+ # Role types the user form doesn't render (assigned in organizer dashboards), e.g. check-in groups and preview.
32
+ NON_FORM_ROLE_TYPES = %i[check_in preview].freeze
33
+
34
+ # spree_role_ids= replaces the whole role set, so a submit that omits these would drop them. Merge
35
+ # the user's existing ones back in so they survive. Skip when the form didn't submit roles at all.
36
+ def preserve_non_form_roles
37
+ return if params.dig(:user, :spree_role_ids).nil?
38
+
39
+ preserved_ids = @user.spree_roles.where(role_type: NON_FORM_ROLE_TYPES).pluck(:id).map(&:to_s)
40
+ params[:user][:spree_role_ids] = (params[:user][:spree_role_ids] + preserved_ids).uniq
41
+ end
42
+
25
43
  def build_profile
26
44
  return unless permitted_resource_params[:profile]
27
45