spree_cm_commissioner 2.13.3 → 2.13.4

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 (283) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +0 -1
  3. data/Gemfile.lock +1 -1
  4. data/app/assets/config/spree_cm_commissioner_manifest.js +0 -1
  5. data/app/assets/javascripts/spree_cm_commissioner/backend.js +0 -8
  6. data/app/assets/stylesheets/spree_cm_commissioner/backend/commissioner_admin.css.scss +0 -1
  7. data/app/controllers/concerns/spree_cm_commissioner/content_cachable.rb +10 -8
  8. data/app/controllers/spree/admin/base_controller_decorator.rb +0 -12
  9. data/app/controllers/spree/admin/oauth_application_api_keys_controller.rb +118 -0
  10. data/app/controllers/spree/admin/oauth_applications_controller.rb +10 -0
  11. data/app/controllers/spree/api/v2/storefront/dynamic_field_options_controller.rb +12 -0
  12. data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +0 -5
  13. data/app/controllers/spree/api/v2/tenant/trip_search_controller.rb +0 -5
  14. data/app/helpers/spree/{billing → admin}/navigation_helper_decorator.rb +2 -9
  15. data/app/interactors/spree_cm_commissioner/user_acleda_bank_web_app_authenticator.rb +38 -0
  16. data/app/interactors/spree_cm_commissioner/user_wing_bank_web_app_authenticator.rb +39 -0
  17. data/app/models/concerns/spree_cm_commissioner/oauth_application/mini_app.rb +72 -0
  18. data/app/models/spree_cm_commissioner/dynamic_field.rb +12 -1
  19. data/app/models/spree_cm_commissioner/dynamic_field_option.rb +11 -0
  20. data/app/models/spree_cm_commissioner/guest.rb +8 -0
  21. data/app/models/spree_cm_commissioner/mini_app_provider/acleda_bank.rb +28 -0
  22. data/app/models/spree_cm_commissioner/mini_app_provider/base.rb +219 -0
  23. data/app/models/spree_cm_commissioner/mini_app_provider/vattanac_bank.rb +6 -0
  24. data/app/models/spree_cm_commissioner/mini_app_provider/wing_bank.rb +30 -0
  25. data/app/models/spree_cm_commissioner/oauth_application_decorator.rb +7 -0
  26. data/app/models/spree_cm_commissioner/product_dynamic_field.rb +9 -0
  27. data/app/models/spree_cm_commissioner/user_identity_provider.rb +1 -1
  28. data/app/services/spree_cm_commissioner/mini_app_provider/api_key_history.rb +128 -0
  29. data/app/services/spree_cm_commissioner/mini_app_provider/ip_rules.rb +26 -0
  30. data/app/services/spree_cm_commissioner/mini_app_provider/session_gate.rb +79 -0
  31. data/app/services/spree_cm_commissioner/mini_app_provider/session_throttle.rb +66 -0
  32. data/app/services/spree_cm_commissioner/payment_method_type_mapper.rb +3 -1
  33. data/app/services/spree_cm_commissioner/rate_limiter/result.rb +20 -0
  34. data/app/services/spree_cm_commissioner/rate_limiter.rb +62 -0
  35. data/app/services/spree_cm_commissioner/seeds/user_usernames.rb +3 -1
  36. data/app/services/spree_cm_commissioner/ticket_transfers/eligibility_checker.rb +5 -6
  37. data/app/services/spree_cm_commissioner/ticket_transfers/preview_rule.rb +3 -5
  38. data/app/services/spree_cm_commissioner/user_authenticator.rb +12 -2
  39. data/app/services/spree_cm_commissioner/wing_mini_app/config.rb +44 -0
  40. data/app/services/spree_cm_commissioner/wing_mini_app/find_or_create_user.rb +89 -0
  41. data/app/services/spree_cm_commissioner/wing_mini_app/profile_verifier.rb +65 -0
  42. data/app/views/spree/admin/guests/_table.html.erb +4 -0
  43. data/app/views/spree/admin/oauth_applications/_api_key_minted_modal.html.erb +71 -0
  44. data/app/views/spree/admin/oauth_applications/_api_key_modal.html.erb +68 -0
  45. data/app/views/spree/admin/oauth_applications/_api_key_restore_list.html.erb +40 -0
  46. data/app/views/spree/admin/oauth_applications/_api_key_restore_modal.html.erb +72 -0
  47. data/app/views/spree/admin/oauth_applications/_api_key_revoke_modal.html.erb +54 -0
  48. data/app/views/spree/admin/oauth_applications/_form.html.erb +152 -0
  49. data/app/views/spree/admin/oauth_applications/edit.html.erb +36 -0
  50. data/app/views/spree/admin/shared/_ticket_transfer_details.html.erb +8 -2
  51. data/config/locales/en.yml +12 -0
  52. data/config/routes.rb +15 -113
  53. data/db/migrate/20260928070109_add_provider_and_api_key_to_spree_oauth_applications.rb +11 -0
  54. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +16 -2
  55. data/lib/spree_cm_commissioner/version.rb +1 -1
  56. data/lib/spree_cm_commissioner.rb +8 -1
  57. metadata +28 -229
  58. data/app/assets/javascripts/spree_cm_commissioner/address_hide_form.js +0 -17
  59. data/app/assets/javascripts/spree_cm_commissioner/location_checkbox_manager.js +0 -45
  60. data/app/assets/javascripts/spree_cm_commissioner/report_hide_filter.js +0 -37
  61. data/app/assets/javascripts/spree_cm_commissioner/role_form.js +0 -51
  62. data/app/assets/javascripts/spree_cm_commissioner/selected_field_filter_origin_destination.js +0 -37
  63. data/app/assets/javascripts/spree_cm_commissioner/trip_stop_selection.js +0 -41
  64. data/app/assets/javascripts/spree_cm_commissioner/update_popup_confirmation.js +0 -42
  65. data/app/assets/javascripts/spree_cm_commissioner/vehicle_seat.js +0 -291
  66. data/app/assets/stylesheets/spree_cm_commissioner/backend/invoice.scss +0 -92
  67. data/app/assets/stylesheets/spree_cm_commissioner/backend/vehicle_seat.scss +0 -28
  68. data/app/controllers/concerns/spree/billing/order_parents_concern.rb +0 -31
  69. data/app/controllers/concerns/spree/billing/payment_creatable.rb +0 -64
  70. data/app/controllers/concerns/spree/billing/payment_fireable.rb +0 -35
  71. data/app/controllers/concerns/spree_cm_commissioner/billing/role_authorization.rb +0 -53
  72. data/app/controllers/spree/billing/addresses_controller.rb +0 -32
  73. data/app/controllers/spree/billing/adjustments_controller.rb +0 -72
  74. data/app/controllers/spree/billing/base_controller.rb +0 -82
  75. data/app/controllers/spree/billing/businesses_controller.rb +0 -135
  76. data/app/controllers/spree/billing/customers_controller.rb +0 -107
  77. data/app/controllers/spree/billing/errors_controller.rb +0 -14
  78. data/app/controllers/spree/billing/invoice_controller.rb +0 -36
  79. data/app/controllers/spree/billing/option_types_controller.rb +0 -32
  80. data/app/controllers/spree/billing/orders_controller.rb +0 -90
  81. data/app/controllers/spree/billing/payment_qrcodes_controller.rb +0 -14
  82. data/app/controllers/spree/billing/payments_controller.rb +0 -148
  83. data/app/controllers/spree/billing/places_controller.rb +0 -35
  84. data/app/controllers/spree/billing/products_controller.rb +0 -56
  85. data/app/controllers/spree/billing/refunds_controller.rb +0 -9
  86. data/app/controllers/spree/billing/reports_controller.rb +0 -202
  87. data/app/controllers/spree/billing/roles_controller.rb +0 -107
  88. data/app/controllers/spree/billing/store_credits_controller.rb +0 -117
  89. data/app/controllers/spree/billing/subscriptions_controller.rb +0 -49
  90. data/app/controllers/spree/billing/users_controller.rb +0 -19
  91. data/app/controllers/spree/billing/variants_controller.rb +0 -36
  92. data/app/controllers/spree/billing/vendors_controller.rb +0 -83
  93. data/app/controllers/spree/transit/amenities_controller.rb +0 -79
  94. data/app/controllers/spree/transit/amenity_values_controller.rb +0 -16
  95. data/app/controllers/spree/transit/base_controller.rb +0 -53
  96. data/app/controllers/spree/transit/branches_controller.rb +0 -35
  97. data/app/controllers/spree/transit/locations_controller.rb +0 -38
  98. data/app/controllers/spree/transit/places_controller.rb +0 -151
  99. data/app/controllers/spree/transit/reservations_controller.rb +0 -15
  100. data/app/controllers/spree/transit/routes_controller.rb +0 -66
  101. data/app/controllers/spree/transit/service_calendars_controller.rb +0 -109
  102. data/app/controllers/spree/transit/stops_controller.rb +0 -32
  103. data/app/controllers/spree/transit/trip_stops_controller.rb +0 -35
  104. data/app/controllers/spree/transit/trips_controller.rb +0 -90
  105. data/app/controllers/spree/transit/vectors/amenity_values_controller.rb +0 -40
  106. data/app/controllers/spree/transit/vectors/icons_controller.rb +0 -26
  107. data/app/controllers/spree/transit/vehicle_photos_controller.rb +0 -52
  108. data/app/controllers/spree/transit/vehicle_seats_controller.rb +0 -29
  109. data/app/controllers/spree/transit/vehicle_types_controller.rb +0 -81
  110. data/app/controllers/spree/transit/vehicles_controller.rb +0 -54
  111. data/app/controllers/spree/transit/vendors_controller.rb +0 -83
  112. data/app/helpers/spree/billing/sortable_tree_helper.rb +0 -32
  113. data/app/helpers/spree/transit/navigation_helper_decorator.rb +0 -14
  114. data/app/helpers/spree/transit/sortable_tree_helper.rb +0 -32
  115. data/app/helpers/spree_cm_commissioner/billing/monthly_orders_helper.rb +0 -66
  116. data/app/helpers/spree_cm_commissioner/billing/qrcodes_helper.rb +0 -11
  117. data/app/helpers/spree_cm_commissioner/transit/service_calendars_helper.rb +0 -17
  118. data/app/views/spree/billing/addresses/_form.html.erb +0 -38
  119. data/app/views/spree/billing/addresses/index.html.erb +0 -19
  120. data/app/views/spree/billing/adjustments/_adjustment.html.erb +0 -34
  121. data/app/views/spree/billing/adjustments/_adjustments_table.html.erb +0 -32
  122. data/app/views/spree/billing/adjustments/_form.html.erb +0 -12
  123. data/app/views/spree/billing/adjustments/edit.html.erb +0 -13
  124. data/app/views/spree/billing/adjustments/index.html.erb +0 -32
  125. data/app/views/spree/billing/adjustments/new.html.erb +0 -9
  126. data/app/views/spree/billing/businesses/_assets_form.html.erb +0 -8
  127. data/app/views/spree/billing/businesses/_form.html.erb +0 -88
  128. data/app/views/spree/billing/businesses/edit.html.erb +0 -21
  129. data/app/views/spree/billing/businesses/index.html.erb +0 -32
  130. data/app/views/spree/billing/businesses/new.html.erb +0 -16
  131. data/app/views/spree/billing/customers/_form.html.erb +0 -44
  132. data/app/views/spree/billing/customers/edit.html.erb +0 -23
  133. data/app/views/spree/billing/customers/index.html.erb +0 -160
  134. data/app/views/spree/billing/customers/new.html.erb +0 -15
  135. data/app/views/spree/billing/errors/forbidden.html.erb +0 -7
  136. data/app/views/spree/billing/invoice/show.html.erb +0 -21
  137. data/app/views/spree/billing/option_types/_form.html.erb +0 -29
  138. data/app/views/spree/billing/option_types/_option_value_fields.html.erb +0 -13
  139. data/app/views/spree/billing/option_types/edit.html.erb +0 -56
  140. data/app/views/spree/billing/option_types/index.html.erb +0 -50
  141. data/app/views/spree/billing/option_types/new.html.erb +0 -13
  142. data/app/views/spree/billing/orders/_form.html.erb +0 -54
  143. data/app/views/spree/billing/orders/_line_item.html.erb +0 -57
  144. data/app/views/spree/billing/orders/_search.html.erb +0 -62
  145. data/app/views/spree/billing/orders/edit.html.erb +0 -16
  146. data/app/views/spree/billing/orders/index.html.erb +0 -84
  147. data/app/views/spree/billing/orders/show.html.erb +0 -1
  148. data/app/views/spree/billing/payments/_list.html.erb +0 -49
  149. data/app/views/spree/billing/payments/_state_changes.html.erb +0 -33
  150. data/app/views/spree/billing/payments/index.html.erb +0 -35
  151. data/app/views/spree/billing/payments/new.html.erb +0 -24
  152. data/app/views/spree/billing/payments/show.html.erb +0 -15
  153. data/app/views/spree/billing/places/_form.html.erb +0 -16
  154. data/app/views/spree/billing/places/edit.html.erb +0 -12
  155. data/app/views/spree/billing/places/index.html.erb +0 -72
  156. data/app/views/spree/billing/places/new.html.erb +0 -15
  157. data/app/views/spree/billing/products/_add_stock_form.html.erb +0 -40
  158. data/app/views/spree/billing/products/_filters.html.erb +0 -31
  159. data/app/views/spree/billing/products/_form.html.erb +0 -123
  160. data/app/views/spree/billing/products/edit.html.erb +0 -8
  161. data/app/views/spree/billing/products/index.html.erb +0 -72
  162. data/app/views/spree/billing/products/new.html.erb +0 -85
  163. data/app/views/spree/billing/products/stock.html.erb +0 -77
  164. data/app/views/spree/billing/reports/_date_range_picker.html.erb +0 -78
  165. data/app/views/spree/billing/reports/_overview.html.erb +0 -48
  166. data/app/views/spree/billing/reports/active_subscribers.html.erb +0 -97
  167. data/app/views/spree/billing/reports/balance_due.html.erb +0 -188
  168. data/app/views/spree/billing/reports/export.html.erb +0 -70
  169. data/app/views/spree/billing/reports/failed_orders.html.erb +0 -58
  170. data/app/views/spree/billing/reports/index.html.erb +0 -62
  171. data/app/views/spree/billing/reports/overdue.html.erb +0 -61
  172. data/app/views/spree/billing/reports/paid.html.erb +0 -60
  173. data/app/views/spree/billing/roles/_form.html.erb +0 -52
  174. data/app/views/spree/billing/roles/edit.html.erb +0 -13
  175. data/app/views/spree/billing/roles/index.html.erb +0 -44
  176. data/app/views/spree/billing/roles/new.html.erb +0 -13
  177. data/app/views/spree/billing/shared/_customer_credit_form.html.erb +0 -33
  178. data/app/views/spree/billing/shared/_customer_promotion_form.html.erb +0 -29
  179. data/app/views/spree/billing/shared/_customer_promotion_table.html.erb +0 -39
  180. data/app/views/spree/billing/shared/_customer_tabs.html.erb +0 -46
  181. data/app/views/spree/billing/shared/_header.html.erb +0 -21
  182. data/app/views/spree/billing/shared/_invoice.html.erb +0 -280
  183. data/app/views/spree/billing/shared/_language_switcher.html.erb +0 -5
  184. data/app/views/spree/billing/shared/_main_menu.html.erb +0 -73
  185. data/app/views/spree/billing/shared/_order_tabs.html.erb +0 -41
  186. data/app/views/spree/billing/shared/_pop_up_confirmation.html.erb +0 -103
  187. data/app/views/spree/billing/shared/_product_tabs.html.erb +0 -24
  188. data/app/views/spree/billing/shared/_role_tabs.html.erb +0 -13
  189. data/app/views/spree/billing/shared/_subscription_tabs.html.erb +0 -20
  190. data/app/views/spree/billing/shared/_user_tabs.html.erb +0 -13
  191. data/app/views/spree/billing/shared/_vendor_logo.html.erb +0 -1
  192. data/app/views/spree/billing/shared/_vendor_switcher.html.erb +0 -57
  193. data/app/views/spree/billing/shared/sortable_tree/_taxonomy.html.erb +0 -29
  194. data/app/views/spree/billing/shared/sub_menu/_product.html.erb +0 -8
  195. data/app/views/spree/billing/shared/sub_menu/_report.html.erb +0 -23
  196. data/app/views/spree/billing/shared/sub_menu/_setting.html.erb +0 -11
  197. data/app/views/spree/billing/store_credits/_form.html.erb +0 -11
  198. data/app/views/spree/billing/store_credits/index.html.erb +0 -44
  199. data/app/views/spree/billing/store_credits/new.html.erb +0 -17
  200. data/app/views/spree/billing/subscriptions/_form.html.erb +0 -27
  201. data/app/views/spree/billing/subscriptions/_subscribed_variants_table.html.erb +0 -24
  202. data/app/views/spree/billing/subscriptions/edit.html.erb +0 -12
  203. data/app/views/spree/billing/subscriptions/index.html.erb +0 -86
  204. data/app/views/spree/billing/subscriptions/new.html.erb +0 -21
  205. data/app/views/spree/billing/users/_form.html.erb +0 -64
  206. data/app/views/spree/billing/users/edit.html.erb +0 -25
  207. data/app/views/spree/billing/users/index.html.erb +0 -116
  208. data/app/views/spree/billing/users/new.html.erb +0 -17
  209. data/app/views/spree/billing/variants/_form.html.erb +0 -28
  210. data/app/views/spree/billing/variants/edit.html.erb +0 -15
  211. data/app/views/spree/billing/variants/index.html.erb +0 -66
  212. data/app/views/spree/billing/variants/new.html.erb +0 -15
  213. data/app/views/spree/billing/vendors/_form.html.erb +0 -75
  214. data/app/views/spree/billing/vendors/edit.html.erb +0 -9
  215. data/app/views/spree/layouts/billing.html.erb +0 -74
  216. data/app/views/spree/layouts/transit.html.erb +0 -74
  217. data/app/views/spree/transit/amenities/_form.html.erb +0 -50
  218. data/app/views/spree/transit/amenities/_option_value_fields.html.erb +0 -15
  219. data/app/views/spree/transit/amenities/edit.html.erb +0 -53
  220. data/app/views/spree/transit/branches/_filter_form.erb +0 -23
  221. data/app/views/spree/transit/branches/_form.html.erb +0 -36
  222. data/app/views/spree/transit/branches/edit.html.erb +0 -15
  223. data/app/views/spree/transit/branches/index.html.erb +0 -43
  224. data/app/views/spree/transit/branches/new.html.erb +0 -19
  225. data/app/views/spree/transit/locations/_filter_form.erb +0 -30
  226. data/app/views/spree/transit/locations/_form.html.erb +0 -19
  227. data/app/views/spree/transit/locations/edit.html.erb +0 -15
  228. data/app/views/spree/transit/locations/index.html.erb +0 -49
  229. data/app/views/spree/transit/locations/new.html.erb +0 -17
  230. data/app/views/spree/transit/places/_assets_form.html.erb +0 -8
  231. data/app/views/spree/transit/places/_form.html.erb +0 -128
  232. data/app/views/spree/transit/places/edit.html.erb +0 -21
  233. data/app/views/spree/transit/places/index.html.erb +0 -32
  234. data/app/views/spree/transit/places/new.html.erb +0 -16
  235. data/app/views/spree/transit/reservations/index.html.erb +0 -5
  236. data/app/views/spree/transit/routes/_filter_form.erb +0 -24
  237. data/app/views/spree/transit/routes/_form.html.erb +0 -74
  238. data/app/views/spree/transit/routes/edit.html.erb +0 -13
  239. data/app/views/spree/transit/routes/index.html.erb +0 -79
  240. data/app/views/spree/transit/routes/new.html.erb +0 -18
  241. data/app/views/spree/transit/service_calendars/_exception_rules.html.erb +0 -44
  242. data/app/views/spree/transit/service_calendars/_filters.html.erb +0 -17
  243. data/app/views/spree/transit/service_calendars/_form.html.erb +0 -107
  244. data/app/views/spree/transit/service_calendars/index.html.erb +0 -77
  245. data/app/views/spree/transit/service_calendars/new.html.erb +0 -13
  246. data/app/views/spree/transit/shared/_amenity_tabs.html.erb +0 -21
  247. data/app/views/spree/transit/shared/_header.html.erb +0 -20
  248. data/app/views/spree/transit/shared/_main_menu.html.erb +0 -34
  249. data/app/views/spree/transit/shared/_route_tabs.html.erb +0 -25
  250. data/app/views/spree/transit/shared/_vehicle_tabs.html.erb +0 -15
  251. data/app/views/spree/transit/shared/_vendor_switcher.html.erb +0 -40
  252. data/app/views/spree/transit/shared/sortable_tree/_taxonomy.html.erb +0 -29
  253. data/app/views/spree/transit/shared/sub_menu/_setting.html.erb +0 -3
  254. data/app/views/spree/transit/stops/_filters.html.erb +0 -33
  255. data/app/views/spree/transit/stops/_form.html.erb +0 -68
  256. data/app/views/spree/transit/stops/edit.html.erb +0 -16
  257. data/app/views/spree/transit/stops/index.html.erb +0 -58
  258. data/app/views/spree/transit/stops/new.html.erb +0 -16
  259. data/app/views/spree/transit/trip_stops/index.html.erb +0 -38
  260. data/app/views/spree/transit/trips/_form.html.erb +0 -82
  261. data/app/views/spree/transit/trips/edit.html.erb +0 -15
  262. data/app/views/spree/transit/trips/new.html.erb +0 -15
  263. data/app/views/spree/transit/vectors/amenity_values/index.html.erb +0 -111
  264. data/app/views/spree/transit/vehicle_photos/_form.html.erb +0 -22
  265. data/app/views/spree/transit/vehicle_photos/edit.html.erb +0 -9
  266. data/app/views/spree/transit/vehicle_photos/index.html.erb +0 -61
  267. data/app/views/spree/transit/vehicle_photos/new.html.erb +0 -9
  268. data/app/views/spree/transit/vehicle_seats/_form.html.erb +0 -48
  269. data/app/views/spree/transit/vehicle_seats/_seats.html.erb +0 -63
  270. data/app/views/spree/transit/vehicle_types/_filter_form.html.erb +0 -29
  271. data/app/views/spree/transit/vehicle_types/_form.html.erb +0 -65
  272. data/app/views/spree/transit/vehicle_types/_seat_view.erb +0 -83
  273. data/app/views/spree/transit/vehicle_types/edit.html.erb +0 -93
  274. data/app/views/spree/transit/vehicle_types/index.html.erb +0 -94
  275. data/app/views/spree/transit/vehicle_types/new.html.erb +0 -14
  276. data/app/views/spree/transit/vehicles/_filter_form.html.erb +0 -23
  277. data/app/views/spree/transit/vehicles/_form.html.erb +0 -19
  278. data/app/views/spree/transit/vehicles/edit.html.erb +0 -19
  279. data/app/views/spree/transit/vehicles/index.html.erb +0 -57
  280. data/app/views/spree/transit/vehicles/new.html.erb +0 -19
  281. data/app/views/spree/transit/vendors/_form.html.erb +0 -34
  282. data/app/views/spree/transit/vendors/_tabs.html.erb +0 -16
  283. data/app/views/spree/transit/vendors/edit.html.erb +0 -10
@@ -0,0 +1,54 @@
1
+ <%# Outside the application's form — forms cannot nest. Revoking leaves the partner with nothing to
2
+ deploy in place of the old key, so it costs the application's name typed back. The controller
3
+ checks it again — a stale page walks straight past this. %>
4
+
5
+ <div class="modal fade" id="mini-app-api-key-revoke-modal" tabindex="-1" role="dialog"
6
+ aria-labelledby="miniAppApiKeyRevokeModalLabel" aria-hidden="true">
7
+ <div class="modal-dialog" role="document">
8
+ <div class="modal-content">
9
+ <div class="modal-header">
10
+ <h5 class="modal-title" id="miniAppApiKeyRevokeModalLabel">Revoke this API key?</h5>
11
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
12
+ <span aria-hidden="true">&times;</span>
13
+ </button>
14
+ </div>
15
+
16
+ <%= form_with url: spree.admin_oauth_application_api_key_path(application), method: :delete, local: true do %>
17
+ <div class="modal-body">
18
+ <div class="alert alert-danger mb-3">
19
+ The mini app is left with no key at all — unlike Regenerate, nothing takes the old key's place.
20
+ <strong>Nothing the partner sends reaches us until a new key is generated and they deploy it.</strong>
21
+ </div>
22
+
23
+ <div class="form-group mb-0">
24
+ <label>Type the application name <code class="text-danger"><%= application.name %></code> to confirm</label>
25
+ <%= text_field_tag :api_key_confirm, nil, class: 'form-control', autocomplete: 'off',
26
+ id: 'mini-app-api-key-revoke-confirm' %>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="modal-footer">
31
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
32
+ <%= submit_tag 'Revoke key', class: 'btn btn-danger', id: 'mini-app-api-key-revoke-submit' %>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <%# Left enabled in the markup so a script that never runs cannot strand an admin who needs to revoke
40
+ a leaked key; the controller is what actually refuses. %>
41
+ <script>
42
+ (function () {
43
+ var input = document.getElementById('mini-app-api-key-revoke-confirm');
44
+ var submit = document.getElementById('mini-app-api-key-revoke-submit');
45
+ if (!input || !submit) return;
46
+
47
+ var expected = '<%= j application.name %>';
48
+
49
+ function sync() { submit.disabled = input.value.trim() !== expected; }
50
+
51
+ sync();
52
+ input.addEventListener('input', sync);
53
+ })();
54
+ </script>
@@ -0,0 +1,152 @@
1
+ <%# Overrides spree_backend's single-column form to sit the mini app settings beside the
2
+ application's own. `admin_oauth_application_form_fields` has to stay in the left column or the
3
+ tenant deface override (_form/tenant_fields.html.erb.deface) lands away from its fields. %>
4
+
5
+ <div data-hook="oauth_application" class="row">
6
+ <div class="col-12 col-md-6">
7
+ <div class="card mb-3">
8
+ <div class="card-header">
9
+ <h5 class="mb-0"><%= Spree.t(:settings) %></h5>
10
+ </div>
11
+
12
+ <div class="card-body">
13
+ <div data-hook="admin_oauth_application_form_fields">
14
+ <%= f.field_container :name, 'data-hook' => "oauth_application_name" do %>
15
+ <%= f.label :name, raw(Spree.t(:name) + required_span_tag) %>
16
+ <%= f.text_field :name, class: 'form-control', required: true %>
17
+ <%= f.error_message_on :name %>
18
+ <% end %>
19
+
20
+ <%= f.field_container :scopes, 'data-hook' => "oauth_application_scopes" do %>
21
+ <%= f.label :scopes, raw(Spree.t(:scopes) + required_span_tag) %>
22
+ <%= f.text_field :scopes, class: 'form-control' %>
23
+ <%= f.error_message_on :scopes %>
24
+ <small class="form-text text-muted">
25
+ Possible values:
26
+ <ul>
27
+ <li><strong>admin read</strong> - read only access</li>
28
+ <li><strong>admin write</strong> - read and write access</li>
29
+ </ul>
30
+ </small>
31
+ <% end %>
32
+
33
+ <div data-hook="additional_oauth_application_fields"></div>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="col-12 col-md-6">
40
+ <%# Mirrors the payment method form's provider settings card. The provider names which mini app
41
+ this application stands for, and the fields below come from that mini app's own class under
42
+ SpreeCmCommissioner::MiniAppProvider — the stand-in for a gateway owning its preferences by
43
+ its own class. %>
44
+
45
+ <% mini_app = f.object.mini_app %>
46
+
47
+ <div data-hook="admin_oauth_application_mini_app" class="card mb-3">
48
+ <div class="card-header">
49
+ <h5 class="mb-0">Mini App</h5>
50
+ </div>
51
+
52
+ <div class="card-body">
53
+ <%= f.field_container :provider do %>
54
+ <%= f.label :provider, 'Provider' %>
55
+ <%= f.select :provider, SpreeCmCommissioner::MiniAppProvider::Base.providers.map(&:provider), { include_blank: 'None' }, { class: 'form-control' } %>
56
+ <%= f.error_message_on :provider %>
57
+ <% end %>
58
+
59
+ <div id="mini-app-settings" data-hook>
60
+ <% unless mini_app.nil? %>
61
+ <% if mini_app.preference_groups.empty? %>
62
+ <small class="form-text text-muted">
63
+ Nothing else to set here — this mini app's remaining settings come from the environment.
64
+ </small>
65
+ <% else %>
66
+ <%= f.fields_for :mini_app_attributes, mini_app do |pf| %>
67
+ <% headings = { credentials: 'Credentials',
68
+ ip_rules: 'IP rules',
69
+ rate_limits: 'Rate limits (per minute, 0 to turn off)' } %>
70
+ <%# Examples rather than a rule in the heading, so the format is in front of
71
+ whoever is typing. preference_field_for cannot carry one. %>
72
+ <% placeholders = { allowed_ips: '203.0.113.0/24, 198.51.100.7', blocked_ips: '198.51.100.9' } %>
73
+
74
+ <%# humanize alone drops a trailing _id and lowercases every acronym. The
75
+ trailing group keeps a plural's s lowercase: IPs, not IPS. %>
76
+ <% acronyms = /\b(id|ip|api)(s?)\b/i %>
77
+
78
+ <% mini_app.preference_groups.each do |group, names| %>
79
+ <h6 class="text-muted mt-4"><%= headings.fetch(group, group.to_s.humanize) %></h6>
80
+
81
+ <% names.each do |name| %>
82
+ <div class="form-group" id="<%= "mini-app-preference-#{name}" %>">
83
+ <%= pf.label "preferred_#{name}", name.to_s.humanize(keep_id_suffix: true).gsub(acronyms) { "#{Regexp.last_match(1).upcase}#{Regexp.last_match(2)}" } %>
84
+ <% if placeholders[name] %>
85
+ <%= pf.text_field "preferred_#{name}", class: 'form-control', placeholder: placeholders[name] %>
86
+ <% else %>
87
+ <%= preference_field_for(pf, "preferred_#{name}", type: mini_app.preference_type(name)) %>
88
+ <% end %>
89
+ </div>
90
+ <% end %>
91
+ <% end %>
92
+ <% end %>
93
+ <% end %>
94
+
95
+ <%# Last in the card, under everything the admin types here. The field carries no name, so
96
+ this form cannot submit the key however it is edited — Generate, Restore and Revoke each
97
+ post to an action of their own, from a dialog outside this form. %>
98
+ <% if mini_app.supports_api_key? %>
99
+ <% has_key = mini_app.api_key.present? %>
100
+
101
+ <h6 class="text-muted mt-4">API key</h6>
102
+
103
+ <%# `row` without `form-group`: the caption underneath belongs to the field and reads as
104
+ one block with it, which form-group's bottom margin pulls apart. %>
105
+ <div class="row align-items-center" id="mini-app-api-key">
106
+ <div class="col">
107
+ <%# A mask, never the key: it is on screen once, in the dialog that follows minting. The
108
+ last four characters stay, so the stored key can be checked against the one the
109
+ partner quotes back without putting it on the page. %>
110
+ <%= tag.input type: 'text', class: 'form-control', readonly: true,
111
+ id: 'mini-app-api-key-value', value: mini_app.masked_api_key,
112
+ placeholder: 'Not generated yet' %>
113
+ </div>
114
+
115
+ <% if f.object.persisted? %>
116
+ <div class="col-auto pl-0">
117
+ <button type="button" class="btn <%= has_key ? 'btn-outline-danger' : 'btn-outline-primary' %>"
118
+ data-toggle="modal" data-target="#mini-app-api-key-modal">
119
+ <%= has_key ? 'Regenerate' : 'Generate' %>
120
+ </button>
121
+
122
+ <% if has_key %>
123
+ <button type="button" class="btn btn-outline-danger"
124
+ data-toggle="modal" data-target="#mini-app-api-key-revoke-modal">
125
+ Revoke
126
+ </button>
127
+ <% end %>
128
+
129
+ <button type="button" class="btn btn-outline-secondary" id="mini-app-api-key-restore-open"
130
+ data-toggle="modal" data-target="#mini-app-api-key-restore-modal">
131
+ Restore
132
+ </button>
133
+ </div>
134
+ <% end %>
135
+ </div>
136
+
137
+ <% if f.object.persisted? && has_key %>
138
+ <small class="form-text text-muted mt-1 mb-0"><%= mini_app.api_key_provenance %></small>
139
+ <% end %>
140
+
141
+ <% unless f.object.persisted? %>
142
+ <small class="form-text text-muted mt-1 mb-0">Save the application first, then generate its key.</small>
143
+ <% end %>
144
+
145
+
146
+ <% end %>
147
+ <% end %>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </div>
@@ -0,0 +1,36 @@
1
+ <%# Overrides spree_backend's template only to render the API key dialogs down here: their forms
2
+ post to actions of their own and cannot nest inside the application's. %>
3
+
4
+ <% content_for :page_title do %>
5
+ <%= link_to Spree.t('admin.oauth_applications.list'), spree.admin_oauth_applications_url %> /
6
+ <%= @oauth_application.name.capitalize %>
7
+ <% end %>
8
+
9
+ <%= render partial: 'spree/admin/shared/error_messages', locals: { target: @oauth_application } %>
10
+
11
+ <%= form_for [:admin, @oauth_application] do |f| %>
12
+ <fieldset>
13
+ <%= render partial: 'form', locals: { f: f } %>
14
+ <%= render partial: 'spree/admin/shared/edit_resource_links' %>
15
+ </fieldset>
16
+ <% end %>
17
+
18
+ <% mini_app = @oauth_application.mini_app %>
19
+
20
+ <% if mini_app&.supports_api_key? %>
21
+ <% if @minted_api_key.present? %>
22
+ <%= render partial: 'api_key_minted_modal', locals: { api_key: @minted_api_key } %>
23
+ <% end %>
24
+
25
+ <%= render partial: 'api_key_modal',
26
+ locals: { application: @oauth_application, mini_app: mini_app } %>
27
+
28
+ <%# Restorable even with no key in place: revoking is one of the things it undoes. The list of keys
29
+ is fetched when the dialog opens, so nothing here reads history. %>
30
+ <%= render partial: 'api_key_restore_modal', locals: { application: @oauth_application } %>
31
+
32
+ <% if mini_app.api_key.present? %>
33
+ <%= render partial: 'api_key_revoke_modal',
34
+ locals: { application: @oauth_application } %>
35
+ <% end %>
36
+ <% end %>
@@ -109,7 +109,7 @@
109
109
  <% guest_label = @ticket_transfer.from_guest.display_name_with_bib.presence || "Guest ##{@ticket_transfer.from_guest.id}" %>
110
110
  <% source_order = @ticket_transfer.from_guest.line_item&.order %>
111
111
  <% if source_order %>
112
- <%= link_to guest_label, spree.edit_admin_order_path(source_order.number) %>
112
+ <%= link_to guest_label, spree.admin_order_guests_path(source_order) %>
113
113
  <% else %>
114
114
  <%= guest_label %>
115
115
  <% end %>
@@ -138,7 +138,13 @@
138
138
  <th scope="row">Guest</th>
139
139
  <td>
140
140
  <% if @ticket_transfer.to_guest %>
141
- <%= @ticket_transfer.to_guest.display_name_with_bib.presence || "Guest ##{@ticket_transfer.to_guest.id}" %>
141
+ <% to_guest_label = @ticket_transfer.to_guest.display_name_with_bib.presence || "Guest ##{@ticket_transfer.to_guest.id}" %>
142
+ <% to_order = @ticket_transfer.to_guest.line_item&.order %>
143
+ <% if to_order %>
144
+ <%= link_to to_guest_label, spree.admin_order_guests_path(to_order) %>
145
+ <% else %>
146
+ <%= to_guest_label %>
147
+ <% end %>
142
148
  <% else %>
143
149
  <span class="text-muted">None</span>
144
150
  <% end %>
@@ -1194,3 +1194,15 @@ en:
1194
1194
  service_fee:
1195
1195
  rules:
1196
1196
  rule_already_exists_for_scope: "An active service fee rule already exists for %{scope_type} with currency %{currency}"
1197
+ mini_apps:
1198
+ api_key:
1199
+ unsupported: "This application does not stand for a mini app that uses an API key."
1200
+ stale: "API key left unchanged: it was replaced while this page was open."
1201
+ confirmation_mismatched: "API key left unchanged: the confirmation did not match the application name."
1202
+ saved: "API key saved. Nothing the partner sends reaches us until their calls carry exactly this value."
1203
+ nothing_to_revoke: "There is no API key to revoke."
1204
+ revoked: "API key revoked. The mini app has no way in until a new key is generated and the partner deploys it."
1205
+ restored: "API key restored. The partner's existing key works again — nothing to deploy on their side."
1206
+ not_restorable: "That key could not be read back. It may have been removed, or the encryption keys have changed since."
1207
+ ip_rules:
1208
+ invalid: "%{name} must be addresses or CIDR ranges"
data/config/routes.rb CHANGED
@@ -374,6 +374,12 @@ Spree::Core::Engine.add_routes do
374
374
  resources :ticket_transfers, controller: 'order_ticket_transfers', only: %i[index show]
375
375
  end
376
376
 
377
+ resources :oauth_applications, only: [] do
378
+ resource :api_key, only: %i[create update destroy], controller: :oauth_application_api_keys do
379
+ get :history
380
+ end
381
+ end
382
+
377
383
  resources :user_events, except: %i[show edit update]
378
384
  resources :telegram_bots do
379
385
  member do
@@ -431,119 +437,6 @@ Spree::Core::Engine.add_routes do
431
437
  get '/resource_not_found', to: 'errors#resource_not_found'
432
438
  end
433
439
 
434
- scope '(:locale)', locale: /#{I18n.available_locales.join('|')}/ do
435
- namespace :billing do
436
- resources :reports do
437
- collection do
438
- get :failed_orders
439
- get :paid
440
- get :balance_due
441
- get :overdue
442
- get :active_subscribers
443
- get :export
444
- put :print_all_invoices
445
- get :export_orders
446
- end
447
- end
448
- resources :vendors do
449
- resource :payment_qrcodes, only: %i[destroy]
450
- end
451
- resources :customers do
452
- post 're_create_order', to: 'customers#re_create_order'
453
- post 'apply_promotion', to: 'customers#apply_promotion'
454
- delete 'delete_promotion', to: 'customers#delete_promotion'
455
- resources :orders
456
- resources :subscriptions
457
- resources :addresses
458
- resources :store_credits
459
- end
460
- resources :roles
461
- resources :users do
462
- resource :account_deletions, only: [:destroy]
463
- end
464
- resources :products do
465
- member do
466
- get :stock
467
- end
468
- resources :variants do
469
- collection do
470
- post :update_positions
471
- end
472
- end
473
- resources :refunds, only: %i[new create edit update]
474
- end
475
- resources :variants do
476
- collection do
477
- post :update_positions
478
- end
479
-
480
- resources :variants_including_master, only: [:update]
481
- end
482
- resources :orders do
483
- resource :invoice, only: %i[show create], controller: :invoice do
484
- collection do
485
- put :print_invoice_date
486
- end
487
- end
488
- resources :payments do
489
- resources :refunds, only: %i[new create edit update]
490
- end
491
- resources :adjustments
492
- end
493
- resources :places
494
- put '/switch_vendor', to: 'base#switch_vendor'
495
- get '/forbidden', to: 'errors#forbidden', as: :forbidden
496
- root to: redirect('/billing/reports')
497
- resources :businesses
498
- resources :option_types do
499
- collection do
500
- post :update_positions
501
- post :update_values_positions
502
- end
503
- end
504
- end
505
- end
506
-
507
- namespace :transit do
508
- namespace :vectors do
509
- resources :icons, only: [:index]
510
- resources :amenity_values, only: %i[index update] do
511
- collection do
512
- post :update
513
- end
514
- end
515
- end
516
-
517
- resources :reservations
518
- resources :locations
519
- resources :branches
520
- resources :stops
521
- resources :routes do
522
- resources :trips do
523
- resources :trip_stops do
524
- post :update_sequences, on: :collection
525
- end
526
- end
527
- end
528
- resources :places
529
- resource :amenity, only: %i[new create edit update]
530
- post '/amenity/update_positions'
531
- post '/amenity/update_values_positions'
532
- resources :vehicle_types do
533
- resources :vehicle_seats
534
- end
535
- resources :vehicles do
536
- resources :vehicle_photos do
537
- collection do
538
- post :update_positions
539
- end
540
- end
541
- end
542
- root to: redirect('/transit/reservations')
543
- post '/vehicle_types/vehicle_seats/load_seat', to: 'vehicle_seats#load_seat'
544
- post '/vehicle_types/layer', to: 'vehicle_types#layer'
545
- end
546
-
547
440
  namespace :api, defaults: { format: 'json' } do
548
441
  namespace :v2 do
549
442
  namespace :platform do
@@ -819,8 +712,17 @@ Spree::Core::Engine.add_routes do
819
712
  resources :guests, only: %i[create update show] do
820
713
  resources :id_cards
821
714
  end
715
+
716
+ # deprecated: use the nested dynamic fields under products instead.
822
717
  resources :dynamic_field_options
823
718
  resources :dynamic_fields
719
+
720
+ resources :products, only: [] do
721
+ resources :dynamic_fields, only: :index do
722
+ resources :dynamic_field_options, only: :index
723
+ end
724
+ end
725
+
824
726
  resources :user_guests do
825
727
  resources :id_cards
826
728
  end
@@ -0,0 +1,11 @@
1
+ class AddProviderAndApiKeyToSpreeOauthApplications < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_column :spree_oauth_applications, :provider, :string, if_not_exists: true
4
+ add_column :spree_oauth_applications, :api_key, :string, if_not_exists: true
5
+
6
+ add_index :spree_oauth_applications, :provider, unique: true, if_not_exists: true,
7
+ where: "provider IS NOT NULL AND provider <> ''"
8
+ add_index :spree_oauth_applications, :api_key, unique: true, if_not_exists: true,
9
+ where: 'api_key IS NOT NULL'
10
+ end
11
+ end
@@ -1,13 +1,27 @@
1
+ FactoryBot.define do
2
+ # Spree::Vendor validates name uniqueness. One shared counter keeps names unique across every
3
+ # vendor factory; FFaker::Company.name alone repeats, and "#{n}#{rand}" collides (1+"23" vs 12+"3").
4
+ sequence(:vendor_name) { |n| "#{FFaker::Company.name} #{n}" }
5
+ end
6
+
7
+ # spree_multi_vendor's :vendor factory (used directly by e.g. cm_vehicle_type) names vendors with a
8
+ # bare FFaker::Company.name, which made specs creating several vendors fail at random.
9
+ FactoryBot.modify do
10
+ factory :vendor do
11
+ name { generate(:vendor_name) }
12
+ end
13
+ end
14
+
1
15
  FactoryBot.define do
2
16
  factory :cm_transit_vendor, parent: :vendor do
3
17
  from_email { FFaker::Internet.email } # required only when tenant exist.
4
- sequence(:name) { |n| "#{FFaker::Company.name} #{n}#{Kernel.rand(9999)}" }
18
+ name { generate(:vendor_name) }
5
19
  state { :active }
6
20
  primary_product_type { :transit }
7
21
  end
8
22
 
9
23
  factory :cm_vendor, parent: :vendor do
10
- sequence(:name) { |n| "#{FFaker::Company.name} #{n}#{Kernel.rand(9999)}" }
24
+ name { generate(:vendor_name) }
11
25
  from_email { FFaker::Internet.email } # required only when tenant exist.
12
26
  state { :active }
13
27
  default_state_id { Spree::State.first&.id }
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- VERSION = '2.13.3'.freeze
2
+ VERSION = '2.13.4'.freeze
3
3
 
4
4
  module_function
5
5
 
@@ -69,7 +69,7 @@ require 'byebug' if Rails.env.development? || Rails.env.test?
69
69
  module SpreeCmCommissioner
70
70
  class << self
71
71
  # Allows overriding the default Redis connection pools with custom ones
72
- attr_writer :inventory_redis_pool, :voting_redis_pool
72
+ attr_writer :inventory_redis_pool, :voting_redis_pool, :redis_pool
73
73
 
74
74
  # Inventory Redis pool for inventory management
75
75
  def inventory_redis_pool
@@ -81,10 +81,17 @@ module SpreeCmCommissioner
81
81
  @voting_redis_pool ||= default_redis_pool
82
82
  end
83
83
 
84
+ # General-purpose pool for callers with no dedicated pool of their own,
85
+ # e.g. RateLimiter counters.
86
+ def redis_pool
87
+ @redis_pool ||= default_redis_pool
88
+ end
89
+
84
90
  # Resets all Redis pools, useful for testing or reinitialization
85
91
  def reset_redis_pools
86
92
  @inventory_redis_pool = nil
87
93
  @voting_redis_pool = nil
94
+ @redis_pool = nil
88
95
  end
89
96
 
90
97
  private