spree_api 5.3.4 → 5.4.0.beta2
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.
- checksums.yaml +4 -4
- data/README.md +71 -33
- data/Rakefile +25 -0
- data/app/controllers/concerns/spree/api/v3/api_key_authentication.rb +76 -0
- data/app/controllers/concerns/spree/api/v3/error_handler.rb +261 -0
- data/app/controllers/concerns/spree/api/v3/http_caching.rb +90 -0
- data/app/controllers/concerns/spree/api/v3/jwt_authentication.rb +118 -0
- data/app/controllers/concerns/spree/api/v3/locale_and_currency.rb +185 -0
- data/app/controllers/concerns/spree/api/v3/order_concern.rb +51 -0
- data/app/controllers/concerns/spree/api/v3/resource_serializer.rb +41 -0
- data/app/controllers/concerns/spree/api/v3/security_headers.rb +22 -0
- data/app/controllers/spree/api/v3/base_controller.rb +45 -0
- data/app/controllers/spree/api/v3/resource_controller.rb +210 -0
- data/app/controllers/spree/api/v3/store/auth_controller.rb +146 -0
- data/app/controllers/spree/api/v3/store/base_controller.rb +23 -0
- data/app/controllers/spree/api/v3/store/cart_controller.rb +93 -0
- data/app/controllers/spree/api/v3/store/countries_controller.rb +31 -0
- data/app/controllers/spree/api/v3/store/currencies_controller.rb +18 -0
- data/app/controllers/spree/api/v3/store/customer/account_controller.rb +38 -0
- data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +85 -0
- data/app/controllers/spree/api/v3/store/customer/credit_cards_controller.rb +31 -0
- data/app/controllers/spree/api/v3/store/customer/gift_cards_controller.rb +36 -0
- data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +35 -0
- data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +83 -0
- data/app/controllers/spree/api/v3/store/digitals_controller.rb +37 -0
- data/app/controllers/spree/api/v3/store/locales_controller.rb +24 -0
- data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +68 -0
- data/app/controllers/spree/api/v3/store/orders/line_items_controller.rb +93 -0
- data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +43 -0
- data/app/controllers/spree/api/v3/store/orders/payment_sessions_controller.rb +96 -0
- data/app/controllers/spree/api/v3/store/orders/payments_controller.rb +45 -0
- data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +53 -0
- data/app/controllers/spree/api/v3/store/orders/store_credits_controller.rb +42 -0
- data/app/controllers/spree/api/v3/store/orders_controller.rb +127 -0
- data/app/controllers/spree/api/v3/store/products/filters_controller.rb +38 -0
- data/app/controllers/spree/api/v3/store/products_controller.rb +74 -0
- data/app/controllers/spree/api/v3/store/resource_controller.rb +12 -0
- data/app/controllers/spree/api/v3/store/stores_controller.rb +26 -0
- data/app/controllers/spree/api/v3/store/taxonomies_controller.rb +19 -0
- data/app/controllers/spree/api/v3/store/taxons/products_controller.rb +37 -0
- data/app/controllers/spree/api/v3/store/taxons_controller.rb +34 -0
- data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +33 -0
- data/app/controllers/spree/api/v3/store/wishlists_controller.rb +41 -0
- data/app/jobs/spree/api_keys/mark_as_used.rb +15 -0
- data/app/serializers/spree/api/v3/address_serializer.rb +22 -0
- data/app/serializers/spree/api/v3/admin/customer_serializer.rb +43 -0
- data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/admin/metafield_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +46 -0
- data/app/serializers/spree/api/v3/admin/price_serializer.rb +21 -0
- data/app/serializers/spree/api/v3/admin/product_serializer.rb +47 -0
- data/app/serializers/spree/api/v3/admin/taxon_serializer.rb +20 -0
- data/app/serializers/spree/api/v3/admin/taxonomy_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/admin/variant_serializer.rb +44 -0
- data/app/serializers/spree/api/v3/asset_serializer.rb +20 -0
- data/app/serializers/spree/api/v3/base_serializer.rb +98 -0
- data/app/serializers/spree/api/v3/country_serializer.rb +35 -0
- data/app/serializers/spree/api/v3/credit_card_serializer.rb +12 -0
- data/app/serializers/spree/api/v3/currency_serializer.rb +14 -0
- data/app/serializers/spree/api/v3/customer_return_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/customer_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/digital_link_serializer.rb +30 -0
- data/app/serializers/spree/api/v3/digital_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/export_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/gift_card_serializer.rb +78 -0
- data/app/serializers/spree/api/v3/image_serializer.rb +43 -0
- data/app/serializers/spree/api/v3/import_row_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/import_serializer.rb +32 -0
- data/app/serializers/spree/api/v3/invitation_serializer.rb +47 -0
- data/app/serializers/spree/api/v3/line_item_serializer.rb +48 -0
- data/app/serializers/spree/api/v3/locale_serializer.rb +14 -0
- data/app/serializers/spree/{v2/storefront → api/v3}/metafield_serializer.rb +5 -3
- data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +27 -0
- data/app/serializers/spree/api/v3/option_type_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/option_value_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/order_promotion_serializer.rb +16 -0
- data/app/serializers/spree/api/v3/order_serializer.rb +39 -0
- data/app/serializers/spree/api/v3/payment_method_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/payment_serializer.rb +54 -0
- data/app/serializers/spree/api/v3/payment_session_serializer.rb +32 -0
- data/app/serializers/spree/api/v3/payment_setup_session_serializer.rb +33 -0
- data/app/serializers/spree/api/v3/payment_source_serializer.rb +13 -0
- data/app/serializers/spree/api/v3/price_serializer.rb +34 -0
- data/app/serializers/spree/api/v3/product_serializer.rb +108 -0
- data/app/serializers/spree/api/v3/promotion_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/refund_serializer.rb +31 -0
- data/app/serializers/spree/api/v3/reimbursement_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/report_serializer.rb +29 -0
- data/app/serializers/spree/api/v3/return_authorization_serializer.rb +31 -0
- data/app/serializers/spree/api/v3/return_item_serializer.rb +53 -0
- data/app/serializers/spree/api/v3/shipment_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/shipping_method_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/shipping_rate_serializer.rb +26 -0
- data/app/serializers/spree/api/v3/state_serializer.rb +14 -0
- data/app/serializers/spree/api/v3/stock_item_serializer.rb +23 -0
- data/app/serializers/spree/api/v3/stock_location_serializer.rb +18 -0
- data/app/serializers/spree/api/v3/stock_movement_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/stock_transfer_serializer.rb +25 -0
- data/app/serializers/spree/api/v3/store_credit_serializer.rb +37 -0
- data/app/serializers/spree/api/v3/store_serializer.rb +38 -0
- data/app/serializers/spree/api/v3/taxon_serializer.rb +78 -0
- data/app/serializers/spree/api/v3/taxonomy_serializer.rb +33 -0
- data/app/serializers/spree/api/v3/variant_serializer.rb +86 -0
- data/app/serializers/spree/api/v3/wished_item_serializer.rb +22 -0
- data/app/serializers/spree/api/v3/wishlist_serializer.rb +25 -0
- data/app/services/spree/api/v3/filters_aggregator.rb +156 -0
- data/app/services/spree/api/v3/orders/update.rb +105 -0
- data/config/initializers/alba.rb +5 -0
- data/config/initializers/pagy.rb +10 -0
- data/config/initializers/typelizer.rb +25 -0
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +63 -195
- data/lib/spree/api/configuration.rb +12 -0
- data/lib/spree/api/dependencies.rb +70 -7
- data/lib/spree/api/engine.rb +3 -3
- data/lib/spree/api/middleware/request_size_limit.rb +36 -0
- data/lib/spree/api/openapi/schema_helper.rb +121 -0
- data/lib/spree/api/testing_support/factories.rb +1 -3
- data/lib/spree/api/testing_support/v3/base.rb +121 -0
- data/lib/spree/api.rb +7 -4
- metadata +133 -264
- data/LICENSE.md +0 -57
- data/app/controllers/concerns/spree/api/v2/caching.rb +0 -40
- data/app/controllers/concerns/spree/api/v2/coupon_codes_helper.rb +0 -29
- data/app/controllers/concerns/spree/api/v2/number_resource.rb +0 -11
- data/app/controllers/concerns/spree/api/v2/platform/nested_set_reposition_concern.rb +0 -37
- data/app/controllers/concerns/spree/api/v2/platform/promotion_calculator_params.rb +0 -17
- data/app/controllers/concerns/spree/api/v2/platform/promotion_rule_params.rb +0 -16
- data/app/controllers/concerns/spree/api/v2/product_list_includes.rb +0 -21
- data/app/controllers/concerns/spree/api/v2/storefront/metadata_controller_concern.rb +0 -18
- data/app/controllers/concerns/spree/api/v2/storefront/order_concern.rb +0 -49
- data/app/controllers/spree/api/v2/base_controller.rb +0 -233
- data/app/controllers/spree/api/v2/data_feeds/google_controller.rb +0 -24
- data/app/controllers/spree/api/v2/platform/addresses_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/adjustments_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/classifications_controller.rb +0 -26
- data/app/controllers/spree/api/v2/platform/countries_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/data_feeds_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/digital_links_controller.rb +0 -29
- data/app/controllers/spree/api/v2/platform/digitals_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/gift_cards_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/line_items_controller.rb +0 -63
- data/app/controllers/spree/api/v2/platform/option_types_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/option_values_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/orders_controller.rb +0 -167
- data/app/controllers/spree/api/v2/platform/payment_methods_controller.rb +0 -31
- data/app/controllers/spree/api/v2/platform/payments_controller.rb +0 -21
- data/app/controllers/spree/api/v2/platform/products_controller.rb +0 -41
- data/app/controllers/spree/api/v2/platform/promotion_actions_controller.rb +0 -34
- data/app/controllers/spree/api/v2/platform/promotion_categories_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/promotion_rules_controller.rb +0 -29
- data/app/controllers/spree/api/v2/platform/promotions_controller.rb +0 -35
- data/app/controllers/spree/api/v2/platform/resource_controller.rb +0 -154
- data/app/controllers/spree/api/v2/platform/roles_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/shipments_controller.rb +0 -147
- data/app/controllers/spree/api/v2/platform/shipping_categories_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/shipping_methods_controller.rb +0 -28
- data/app/controllers/spree/api/v2/platform/states_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/stock_items_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/stock_locations_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/store_credit_categories_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/store_credit_types_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/store_credits_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/tax_categories_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/tax_rates_controller.rb +0 -27
- data/app/controllers/spree/api/v2/platform/taxonomies_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/taxons_controller.rb +0 -59
- data/app/controllers/spree/api/v2/platform/users_controller.rb +0 -37
- data/app/controllers/spree/api/v2/platform/variants_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/wished_items_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/wishlists_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/zones_controller.rb +0 -23
- data/app/controllers/spree/api/v2/resource_controller.rb +0 -79
- data/app/controllers/spree/api/v2/storefront/account/addresses_controller.rb +0 -77
- data/app/controllers/spree/api/v2/storefront/account/credit_cards_controller.rb +0 -52
- data/app/controllers/spree/api/v2/storefront/account/orders_controller.rb +0 -50
- data/app/controllers/spree/api/v2/storefront/account_controller.rb +0 -52
- data/app/controllers/spree/api/v2/storefront/cart_controller.rb +0 -246
- data/app/controllers/spree/api/v2/storefront/checkout_controller.rb +0 -183
- data/app/controllers/spree/api/v2/storefront/countries_controller.rb +0 -57
- data/app/controllers/spree/api/v2/storefront/digitals_controller.rb +0 -58
- data/app/controllers/spree/api/v2/storefront/order_status_controller.rb +0 -34
- data/app/controllers/spree/api/v2/storefront/policies_controller.rb +0 -31
- data/app/controllers/spree/api/v2/storefront/post_categories_controller.rb +0 -35
- data/app/controllers/spree/api/v2/storefront/posts_controller.rb +0 -51
- data/app/controllers/spree/api/v2/storefront/products_controller.rb +0 -66
- data/app/controllers/spree/api/v2/storefront/stores_controller.rb +0 -27
- data/app/controllers/spree/api/v2/storefront/taxons_controller.rb +0 -51
- data/app/controllers/spree/api/v2/storefront/variants_controller.rb +0 -41
- data/app/controllers/spree/api/v2/storefront/wishlists_controller.rb +0 -214
- data/app/helpers/spree/api/v2/collection_options_helpers.rb +0 -46
- data/app/helpers/spree/api/v2/display_money_helper.rb +0 -63
- data/app/helpers/spree/api/v2/store_media_serializer_images_concern.rb +0 -30
- data/app/models/concerns/spree/user_api_authentication.rb +0 -19
- data/app/models/concerns/spree/user_api_methods.rb +0 -7
- data/app/models/spree/oauth_access_grant.rb +0 -7
- data/app/models/spree/oauth_access_token.rb +0 -7
- data/app/models/spree/oauth_application.rb +0 -22
- data/app/paginators/spree/api/paginate.rb +0 -68
- data/app/presenters/spree/api/products/filters_presenter.rb +0 -39
- data/app/serializers/concerns/spree/api/v2/image_transformation_concern.rb +0 -15
- data/app/serializers/concerns/spree/api/v2/public_metafields_concern.rb +0 -15
- data/app/serializers/concerns/spree/api/v2/resource_serializer_concern.rb +0 -42
- data/app/serializers/concerns/spree/api/v2/taxon_image_transformation_concern.rb +0 -15
- data/app/serializers/spree/api/v2/base_serializer.rb +0 -43
- data/app/serializers/spree/api/v2/platform/address_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/adjustment_serializer.rb +0 -20
- data/app/serializers/spree/api/v2/platform/admin_user_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/asset_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/base_serializer.rb +0 -10
- data/app/serializers/spree/api/v2/platform/calculator_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/classification_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/country_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/credit_card_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/customer_return_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/data_feed_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/digital_link_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/digital_serializer.rb +0 -29
- data/app/serializers/spree/api/v2/platform/gift_card_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/image_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/inventory_unit_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/line_item_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/log_entry_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/metafield_serializer.rb +0 -21
- data/app/serializers/spree/api/v2/platform/option_type_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/option_value_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/order_promotion_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/order_serializer.rb +0 -31
- data/app/serializers/spree/api/v2/platform/payment_capture_event_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/payment_method_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/payment_serializer.rb +0 -22
- data/app/serializers/spree/api/v2/platform/payment_source_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/price_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/product_property_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/product_serializer.rb +0 -90
- data/app/serializers/spree/api/v2/platform/promotion_action_line_item_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/promotion_action_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/promotion_category_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/promotion_rule_serializer.rb +0 -21
- data/app/serializers/spree/api/v2/platform/promotion_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/property_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/prototype_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/refund_reason_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/refund_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/reimbursement_credit_serializer.rb +0 -10
- data/app/serializers/spree/api/v2/platform/reimbursement_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/reimbursement_type_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/return_authorization_reason_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/return_authorization_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/return_item_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/role_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/shipment_serializer.rb +0 -22
- data/app/serializers/spree/api/v2/platform/shipping_category_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/shipping_method_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/shipping_rate_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/state_change_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/state_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/stock_item_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/stock_location_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/stock_movement_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/stock_transfer_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/store_credit_category_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/store_credit_event_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/store_credit_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/store_credit_type_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/store_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/tax_category_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/tax_rate_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/taxon_image_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/taxon_serializer.rb +0 -47
- data/app/serializers/spree/api/v2/platform/taxonomy_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/user_serializer.rb +0 -37
- data/app/serializers/spree/api/v2/platform/variant_serializer.rb +0 -66
- data/app/serializers/spree/api/v2/platform/wished_item_serializer.rb +0 -29
- data/app/serializers/spree/api/v2/platform/wishlist_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/zone_member_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/zone_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/address_serializer.rb +0 -22
- data/app/serializers/spree/v2/storefront/base_serializer.rb +0 -10
- data/app/serializers/spree/v2/storefront/cart_serializer.rb +0 -67
- data/app/serializers/spree/v2/storefront/country_serializer.rb +0 -24
- data/app/serializers/spree/v2/storefront/credit_card_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/digital_link_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/estimated_shipping_rate_serializer.rb +0 -35
- data/app/serializers/spree/v2/storefront/gift_card_serializer.rb +0 -16
- data/app/serializers/spree/v2/storefront/image_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/line_item_serializer.rb +0 -23
- data/app/serializers/spree/v2/storefront/option_type_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/option_value_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/order_promotion_serializer.rb +0 -14
- data/app/serializers/spree/v2/storefront/order_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/payment_method_serializer.rb +0 -17
- data/app/serializers/spree/v2/storefront/payment_serializer.rb +0 -20
- data/app/serializers/spree/v2/storefront/payment_source_serializer.rb +0 -12
- data/app/serializers/spree/v2/storefront/policy_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/post_category_serializer.rb +0 -23
- data/app/serializers/spree/v2/storefront/post_serializer.rb +0 -51
- data/app/serializers/spree/v2/storefront/product_property_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/product_serializer.rb +0 -92
- data/app/serializers/spree/v2/storefront/shipment_serializer.rb +0 -26
- data/app/serializers/spree/v2/storefront/shipping_category_serializer.rb +0 -10
- data/app/serializers/spree/v2/storefront/shipping_method_serializer.rb +0 -12
- data/app/serializers/spree/v2/storefront/shipping_rate_serializer.rb +0 -26
- data/app/serializers/spree/v2/storefront/state_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/stock_location_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_credit_category_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_credit_event_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/store_credit_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/store_credit_type_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_serializer.rb +0 -18
- data/app/serializers/spree/v2/storefront/taxon_image_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/taxon_serializer.rb +0 -55
- data/app/serializers/spree/v2/storefront/taxonomy_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/user_serializer.rb +0 -33
- data/app/serializers/spree/v2/storefront/variant_serializer.rb +0 -58
- data/app/serializers/spree/v2/storefront/wished_item_serializer.rb +0 -29
- data/app/serializers/spree/v2/storefront/wishlist_serializer.rb +0 -17
- data/config/initializers/doorkeeper.rb +0 -50
- data/config/initializers/json_api_mime_types.rb +0 -8
- data/config/initializers/user_class_extensions.rb +0 -7
- data/db/migrate/20100107141738_add_api_key_to_spree_users.rb +0 -7
- data/db/migrate/20120411123334_resize_api_key_field.rb +0 -7
- data/db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb +0 -7
- data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +0 -7
- data/db/migrate/20180320110726_create_doorkeeper_tables.rb +0 -69
- data/db/migrate/20210727102516_change_integer_id_columns_type.rb +0 -9
- data/db/migrate/20210919183228_enable_polymorphic_resource_owner.rb +0 -21
- data/lib/generators/spree/api/install/install_generator.rb +0 -24
- data/lib/spree/api/testing_support/factories/oauth_application_factory.rb +0 -6
- data/lib/spree/api/testing_support/serializers.rb +0 -15
- data/lib/spree/api/testing_support/v2/base.rb +0 -13
- data/lib/spree/api/testing_support/v2/current_order.rb +0 -116
- data/lib/spree/api/testing_support/v2/platform_contexts.rb +0 -272
- data/lib/spree/api/testing_support/v2/serializers_params.rb +0 -16
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module JwtAuthentication
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
include Spree::Api::V3::ErrorHandler
|
|
8
|
+
|
|
9
|
+
USER_TYPE_CUSTOMER = 'customer'.freeze
|
|
10
|
+
USER_TYPE_ADMIN = 'admin'.freeze
|
|
11
|
+
|
|
12
|
+
JWT_AUDIENCE_STORE = 'store_api'.freeze
|
|
13
|
+
JWT_AUDIENCE_ADMIN = 'admin_api'.freeze
|
|
14
|
+
JWT_ISSUER = 'spree'.freeze
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
attr_reader :current_user
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Optional authentication - doesn't fail if no token
|
|
21
|
+
def authenticate_user
|
|
22
|
+
token = extract_token
|
|
23
|
+
return unless token.present?
|
|
24
|
+
|
|
25
|
+
payload = decode_jwt(token)
|
|
26
|
+
@current_user = find_user_from_payload(payload)
|
|
27
|
+
rescue JWT::DecodeError, JWT::ExpiredSignature, JWT::InvalidIssuerError,
|
|
28
|
+
JWT::InvalidAudError, ActiveRecord::RecordNotFound => e
|
|
29
|
+
Rails.logger.debug { "JWT authentication failed: #{e.message}" }
|
|
30
|
+
@current_user = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Required authentication - fails if no valid token
|
|
34
|
+
# Returns true if authenticated, false otherwise (also renders error and halts)
|
|
35
|
+
def require_authentication!
|
|
36
|
+
authenticate_user
|
|
37
|
+
|
|
38
|
+
return true if current_user
|
|
39
|
+
|
|
40
|
+
render_error(code: ErrorHandler::ERROR_CODES[:authentication_required], message: 'Authentication required', status: :unauthorized)
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
protected
|
|
45
|
+
|
|
46
|
+
# Generate a JWT token for a user
|
|
47
|
+
# @param user [Object] The user to generate a token for
|
|
48
|
+
# @param expiration [Integer] Time in seconds until expiration (default from config, 1 hour)
|
|
49
|
+
# @param audience [String] The audience claim (default: store_api)
|
|
50
|
+
# @return [String] The JWT token
|
|
51
|
+
def generate_jwt(user, expiration: jwt_expiration, audience: JWT_AUDIENCE_STORE)
|
|
52
|
+
payload = {
|
|
53
|
+
user_id: user.id,
|
|
54
|
+
user_type: determine_user_type(user),
|
|
55
|
+
jti: SecureRandom.uuid,
|
|
56
|
+
iss: JWT_ISSUER,
|
|
57
|
+
aud: audience,
|
|
58
|
+
exp: Time.current.to_i + expiration
|
|
59
|
+
}
|
|
60
|
+
JWT.encode(payload, jwt_secret, 'HS256')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def extract_token
|
|
66
|
+
# Check Authorization header first
|
|
67
|
+
header = request.headers['Authorization']
|
|
68
|
+
return header.split(' ').last if header.present? && header.start_with?('Bearer ')
|
|
69
|
+
|
|
70
|
+
# Restricted fallback: only for digital download endpoints
|
|
71
|
+
params[:token] if controller_name == 'digitals'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def decode_jwt(token)
|
|
75
|
+
JWT.decode(token, jwt_secret, true,
|
|
76
|
+
algorithm: 'HS256',
|
|
77
|
+
iss: JWT_ISSUER,
|
|
78
|
+
aud: expected_audience,
|
|
79
|
+
verify_iss: true,
|
|
80
|
+
verify_aud: true
|
|
81
|
+
).first
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def jwt_secret
|
|
85
|
+
Rails.application.credentials.jwt_secret_key || ENV['JWT_SECRET_KEY'] || Rails.application.secret_key_base
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def jwt_expiration
|
|
89
|
+
Spree::Api::Config[:jwt_expiration]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def expected_audience
|
|
93
|
+
JWT_AUDIENCE_STORE
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def find_user_from_payload(payload)
|
|
97
|
+
user_id = payload['user_id']
|
|
98
|
+
user_type = payload['user_type'] || USER_TYPE_CUSTOMER
|
|
99
|
+
|
|
100
|
+
case user_type
|
|
101
|
+
when USER_TYPE_ADMIN
|
|
102
|
+
Spree.admin_user_class.find(user_id)
|
|
103
|
+
else
|
|
104
|
+
Spree.user_class.find(user_id)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def determine_user_type(user)
|
|
109
|
+
if user.is_a?(Spree.admin_user_class)
|
|
110
|
+
USER_TYPE_ADMIN
|
|
111
|
+
else
|
|
112
|
+
USER_TYPE_CUSTOMER
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# Handles locale, currency, and market resolution for API v3 controllers.
|
|
5
|
+
#
|
|
6
|
+
# This concern is fully self-contained and does not depend on
|
|
7
|
+
# +Spree::Core::ControllerHelpers::Locale+ or +Spree::Core::ControllerHelpers::Currency+.
|
|
8
|
+
#
|
|
9
|
+
# Resolution order:
|
|
10
|
+
# 1. Market is resolved from +x-spree-country+ header (sets +Spree::Current.market+)
|
|
11
|
+
# 2. Locale is resolved: +x-spree-locale+ header > +params[:locale]+ > +Spree::Current.locale+ (market -> store fallback)
|
|
12
|
+
# 3. Currency is resolved: +x-spree-currency+ header > +params[:currency]+ > +Spree::Current.currency+ (market -> store fallback)
|
|
13
|
+
# 4. Mobility fallback locale is configured for the current store
|
|
14
|
+
module LocaleAndCurrency
|
|
15
|
+
extend ActiveSupport::Concern
|
|
16
|
+
|
|
17
|
+
included do
|
|
18
|
+
before_action :set_market_from_country
|
|
19
|
+
before_action :set_locale
|
|
20
|
+
before_action :set_currency
|
|
21
|
+
before_action :set_fallback_locale
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
|
|
26
|
+
# Returns the current locale for this request.
|
|
27
|
+
#
|
|
28
|
+
# Priority: x-spree-locale header > params[:locale] > Spree::Current.locale (market -> store fallback)
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the locale code, e.g. +"en"+, +"fr"+
|
|
31
|
+
def current_locale
|
|
32
|
+
@current_locale ||= begin
|
|
33
|
+
locale = locale_from_header || locale_from_params
|
|
34
|
+
locale.to_s if locale.present? && supported_locale?(locale)
|
|
35
|
+
end || Spree::Current.locale
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns the current currency for this request.
|
|
39
|
+
#
|
|
40
|
+
# Priority: x-spree-currency header > params[:currency] > Spree::Current.currency (market -> store fallback)
|
|
41
|
+
#
|
|
42
|
+
# @return [String] the currency ISO code, e.g. +"USD"+, +"EUR"+
|
|
43
|
+
def current_currency
|
|
44
|
+
@current_currency ||= begin
|
|
45
|
+
currency = currency_from_header || currency_from_params
|
|
46
|
+
currency = currency&.upcase
|
|
47
|
+
currency if currency.present? && supported_currency?(currency)
|
|
48
|
+
end || Spree::Current.currency
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns the default locale, delegating to +Spree::Current.locale+
|
|
52
|
+
# which falls back through market -> store.
|
|
53
|
+
#
|
|
54
|
+
# @return [String] the default locale code
|
|
55
|
+
def default_locale
|
|
56
|
+
Spree::Current.locale
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns the list of supported locale codes for the current store.
|
|
60
|
+
#
|
|
61
|
+
# When markets are configured, this aggregates locales from all markets.
|
|
62
|
+
#
|
|
63
|
+
# @return [Array<String>] supported locale codes
|
|
64
|
+
def supported_locales
|
|
65
|
+
@supported_locales ||= current_store&.supported_locales_list
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Checks if the given locale is supported by the current store.
|
|
69
|
+
#
|
|
70
|
+
# @param locale_code [String, nil] the locale code to check
|
|
71
|
+
# @return [Boolean]
|
|
72
|
+
def supported_locale?(locale_code)
|
|
73
|
+
return false if supported_locales.nil?
|
|
74
|
+
|
|
75
|
+
supported_locales.include?(locale_code&.to_s)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns the list of supported currencies for the current store.
|
|
79
|
+
#
|
|
80
|
+
# When markets are configured, this aggregates currencies from all markets.
|
|
81
|
+
#
|
|
82
|
+
# @return [Array<Money::Currency>] supported currencies
|
|
83
|
+
def supported_currencies
|
|
84
|
+
@supported_currencies ||= current_store&.supported_currencies_list
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Checks if the given currency ISO code is supported by the current store.
|
|
88
|
+
#
|
|
89
|
+
# @param currency_iso_code [String, nil] the currency ISO code to check, e.g. +"USD"+
|
|
90
|
+
# @return [Boolean]
|
|
91
|
+
def supported_currency?(currency_iso_code)
|
|
92
|
+
return false if supported_currencies.nil?
|
|
93
|
+
|
|
94
|
+
supported_currencies.map(&:iso_code).include?(currency_iso_code&.upcase)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Finds a record using the given block, falling back to the store's default locale
|
|
98
|
+
# if the record is not found in the current locale.
|
|
99
|
+
#
|
|
100
|
+
# Used for slug/permalink lookups where translated slugs may not exist in all locales.
|
|
101
|
+
#
|
|
102
|
+
# @yield the block that performs the lookup
|
|
103
|
+
# @return [ActiveRecord::Base] the found record
|
|
104
|
+
# @raise [ActiveRecord::RecordNotFound] if not found in any locale
|
|
105
|
+
def find_with_fallback_default_locale(&block)
|
|
106
|
+
result = begin
|
|
107
|
+
block.call
|
|
108
|
+
rescue ActiveRecord::RecordNotFound => _e
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
result || Mobility.with_locale(current_store.default_locale) { block.call }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
# Sets +I18n.locale+ and +Spree::Current.locale+ from the resolved locale.
|
|
118
|
+
def set_locale
|
|
119
|
+
Spree::Current.locale = current_locale
|
|
120
|
+
I18n.locale = current_locale
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Sets +Spree::Current.currency+ from the resolved currency.
|
|
124
|
+
def set_currency
|
|
125
|
+
Spree::Current.currency = current_currency
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Configures Mobility fallback locales for the current store.
|
|
129
|
+
#
|
|
130
|
+
# This runs after market resolution so fallbacks are aware of the store's
|
|
131
|
+
# full locale configuration.
|
|
132
|
+
def set_fallback_locale
|
|
133
|
+
return unless current_store.present?
|
|
134
|
+
|
|
135
|
+
Spree::Locales::SetFallbackLocaleForStore.new.call(store: current_store)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Reads the locale from the +x-spree-locale+ request header.
|
|
139
|
+
#
|
|
140
|
+
# @return [String, nil]
|
|
141
|
+
def locale_from_header
|
|
142
|
+
request.headers['x-spree-locale'].presence
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Reads the currency from the +x-spree-currency+ request header.
|
|
146
|
+
#
|
|
147
|
+
# @return [String, nil]
|
|
148
|
+
def currency_from_header
|
|
149
|
+
request.headers['x-spree-currency'].presence
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Reads the locale from request params.
|
|
153
|
+
#
|
|
154
|
+
# @return [String, nil]
|
|
155
|
+
def locale_from_params
|
|
156
|
+
params[:locale].presence
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Reads the currency from request params.
|
|
160
|
+
#
|
|
161
|
+
# @return [String, nil]
|
|
162
|
+
def currency_from_params
|
|
163
|
+
params[:currency].presence
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Resolves the market from the +x-spree-country+ header or +params[:country]+.
|
|
167
|
+
#
|
|
168
|
+
# When a matching market is found, it is set on +Spree::Current.market+,
|
|
169
|
+
# which influences the default locale and currency fallbacks.
|
|
170
|
+
def set_market_from_country
|
|
171
|
+
country_iso = request.headers['x-spree-country'].presence || params[:country].presence
|
|
172
|
+
return unless country_iso
|
|
173
|
+
|
|
174
|
+
country = Spree::Country.find_by(iso: country_iso.upcase)
|
|
175
|
+
return unless country
|
|
176
|
+
|
|
177
|
+
market = current_store&.market_for_country(country)
|
|
178
|
+
return unless market
|
|
179
|
+
|
|
180
|
+
Spree::Current.market = market
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module OrderConcern
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
# Allow access to order via order token for guests or authenticated users
|
|
8
|
+
# Expects @parent to be set to the order
|
|
9
|
+
def authorize_order_access!
|
|
10
|
+
authorize!(:update, @parent, order_token)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def set_parent
|
|
14
|
+
return if params[:order_id].blank?
|
|
15
|
+
|
|
16
|
+
@parent = order_scope.find_by_prefix_id!(params[:order_id])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def order_scope
|
|
20
|
+
base = current_store.orders
|
|
21
|
+
base = if current_user
|
|
22
|
+
base.where(user: current_user)
|
|
23
|
+
elsif order_token.present?
|
|
24
|
+
base.where(token: order_token)
|
|
25
|
+
else
|
|
26
|
+
base.none
|
|
27
|
+
end
|
|
28
|
+
base.preload_associations_lazily
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
protected
|
|
32
|
+
|
|
33
|
+
# Render the parent order as JSON using the order serializer.
|
|
34
|
+
# Use this when sub-resource mutations should return the updated order
|
|
35
|
+
# (e.g., line items, coupon codes, store credits).
|
|
36
|
+
def render_order(status: :ok)
|
|
37
|
+
render json: Spree.api.order_serializer.new(@parent.reload, params: serializer_params).to_h, status: status
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def order_token
|
|
41
|
+
# Check x-spree-order-token header first (lowercase for consistency)
|
|
42
|
+
header = request.headers['x-spree-order-token']
|
|
43
|
+
return header if header.present?
|
|
44
|
+
|
|
45
|
+
# Fallback to query params (support both token and order_token)
|
|
46
|
+
params[:order_token].presence || params[:token]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module ResourceSerializer
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
protected
|
|
8
|
+
|
|
9
|
+
# Serialize a single resource
|
|
10
|
+
def serialize_resource(resource)
|
|
11
|
+
serializer_class.new(resource, params: serializer_params).to_h
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Serialize a collection of resources
|
|
15
|
+
def serialize_collection(collection)
|
|
16
|
+
collection.map { |item| serializer_class.new(item, params: serializer_params).to_h }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Params passed to serializers
|
|
20
|
+
def serializer_params
|
|
21
|
+
{
|
|
22
|
+
currency: current_currency,
|
|
23
|
+
store: current_store,
|
|
24
|
+
user: current_user,
|
|
25
|
+
locale: current_locale,
|
|
26
|
+
includes: include_list
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Parse include parameter into list
|
|
31
|
+
# Supports: ?include=variants,images or ?includes=variants,images
|
|
32
|
+
def include_list
|
|
33
|
+
include_param = params[:include].presence || params[:includes].presence
|
|
34
|
+
return [] unless include_param
|
|
35
|
+
|
|
36
|
+
include_param.to_s.split(',').map(&:strip)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module SecurityHeaders
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
after_action :set_security_headers
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def set_security_headers
|
|
14
|
+
response.headers['X-Content-Type-Options'] = 'nosniff'
|
|
15
|
+
response.headers['X-Frame-Options'] = 'DENY'
|
|
16
|
+
response.headers.delete('X-Powered-By')
|
|
17
|
+
response.headers.delete('Server')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
class BaseController < ActionController::API
|
|
5
|
+
include ActiveStorage::SetCurrent
|
|
6
|
+
include CanCan::ControllerAdditions
|
|
7
|
+
include Spree::Core::ControllerHelpers::StrongParameters
|
|
8
|
+
include Spree::Core::ControllerHelpers::Store
|
|
9
|
+
include Spree::Api::V3::LocaleAndCurrency
|
|
10
|
+
include Spree::Api::V3::JwtAuthentication
|
|
11
|
+
include Spree::Api::V3::ApiKeyAuthentication
|
|
12
|
+
include Spree::Api::V3::ErrorHandler
|
|
13
|
+
include Spree::Api::V3::HttpCaching
|
|
14
|
+
include Spree::Api::V3::SecurityHeaders
|
|
15
|
+
include Spree::Api::V3::ResourceSerializer
|
|
16
|
+
include Pagy::Method
|
|
17
|
+
|
|
18
|
+
# Optional JWT authentication by default
|
|
19
|
+
before_action :authenticate_user
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
# Override to use current_user from JWT authentication
|
|
24
|
+
# @return [Spree.user_class]
|
|
25
|
+
def spree_current_user
|
|
26
|
+
current_user
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias try_spree_current_user spree_current_user
|
|
30
|
+
|
|
31
|
+
# CanCanCan ability
|
|
32
|
+
# @return [Spree::Ability]
|
|
33
|
+
def current_ability
|
|
34
|
+
@current_ability ||= Spree::Ability.new(current_user, ability_options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Options passed to the CanCanCan ability
|
|
38
|
+
# @return [Hash]
|
|
39
|
+
def ability_options
|
|
40
|
+
{ store: current_store }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
class ResourceController < BaseController
|
|
5
|
+
before_action :set_parent
|
|
6
|
+
before_action :set_resource, only: [:show, :update, :destroy]
|
|
7
|
+
|
|
8
|
+
# GET /api/v3/resource
|
|
9
|
+
def index
|
|
10
|
+
@collection = collection
|
|
11
|
+
|
|
12
|
+
# Apply HTTP caching for guests
|
|
13
|
+
return unless cache_collection(@collection)
|
|
14
|
+
|
|
15
|
+
render json: {
|
|
16
|
+
data: serialize_collection(@collection),
|
|
17
|
+
meta: collection_meta(@collection)
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# GET /api/v3/resource/:id
|
|
22
|
+
def show
|
|
23
|
+
# Apply HTTP caching for guests
|
|
24
|
+
return unless cache_resource(@resource)
|
|
25
|
+
|
|
26
|
+
render json: serialize_resource(@resource)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# POST /api/v3/resource
|
|
30
|
+
def create
|
|
31
|
+
@resource = build_resource
|
|
32
|
+
authorize_resource!(@resource, :create)
|
|
33
|
+
|
|
34
|
+
if @resource.save
|
|
35
|
+
render json: serialize_resource(@resource), status: :created
|
|
36
|
+
else
|
|
37
|
+
render_errors(@resource.errors)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# PATCH /api/v3/resource/:id
|
|
42
|
+
def update
|
|
43
|
+
if @resource.update(permitted_params)
|
|
44
|
+
render json: serialize_resource(@resource)
|
|
45
|
+
else
|
|
46
|
+
render_errors(@resource.errors)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# DELETE /api/v3/resource/:id
|
|
51
|
+
def destroy
|
|
52
|
+
@resource.destroy
|
|
53
|
+
head :no_content
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
|
|
58
|
+
# Override in subclass to set parent resource (e.g., @wishlist, @order)
|
|
59
|
+
# This runs before set_resource, allowing scope to use the parent
|
|
60
|
+
def set_parent
|
|
61
|
+
# No-op by default, override in nested resource controllers
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Sets the resource for show, update, destroy actions
|
|
65
|
+
# Always uses scope to respect controller's custom scoping
|
|
66
|
+
def set_resource
|
|
67
|
+
@resource = find_resource
|
|
68
|
+
authorize_resource!(@resource)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Builds a new resource, using parent association when @parent is set
|
|
72
|
+
def build_resource
|
|
73
|
+
if @parent.present?
|
|
74
|
+
@parent.send(parent_association).build(permitted_params)
|
|
75
|
+
else
|
|
76
|
+
model_class.new(permitted_params)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Finds a single resource within scope using prefixed ID
|
|
81
|
+
def find_resource
|
|
82
|
+
scope.find_by_prefix_id!(params[:id])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Authorize resource with CanCanCan
|
|
86
|
+
def authorize_resource!(resource = @resource, action = action_name.to_sym)
|
|
87
|
+
authorize!(action, resource)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns ransack-filtered, sorted and paginated collection
|
|
91
|
+
# ar_lazy_preload handles automatic association preloading
|
|
92
|
+
# @return [ActiveRecord::Relation]
|
|
93
|
+
def collection
|
|
94
|
+
return @collection if @collection.present?
|
|
95
|
+
|
|
96
|
+
@search = scope.includes(collection_includes).
|
|
97
|
+
preload_associations_lazily.
|
|
98
|
+
ransack(ransack_params)
|
|
99
|
+
result = @search.result(distinct: collection_distinct?)
|
|
100
|
+
result = apply_collection_sort(result)
|
|
101
|
+
@pagy, @collection = pagy(result, limit: limit, page: page)
|
|
102
|
+
@collection
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Override in subclass to disable distinct (e.g., for custom sorting with computed columns)
|
|
106
|
+
def collection_distinct?
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Override in subclass to apply custom sorting
|
|
111
|
+
def apply_collection_sort(collection)
|
|
112
|
+
collection
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def collection_includes
|
|
116
|
+
[]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Ransack query parameters
|
|
120
|
+
def ransack_params
|
|
121
|
+
params[:q] || {}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Pagination parameters
|
|
125
|
+
def page
|
|
126
|
+
params[:page]&.to_i || 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def limit
|
|
130
|
+
limit_param = params[:per_page]&.to_i || params[:limit]&.to_i || 25
|
|
131
|
+
[limit_param, 100].min # Max 100 per page
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Metadata for collection responses
|
|
135
|
+
def collection_meta(_collection)
|
|
136
|
+
return {} unless @pagy
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
page: @pagy.page,
|
|
140
|
+
limit: @pagy.limit,
|
|
141
|
+
count: @pagy.count,
|
|
142
|
+
pages: @pagy.pages,
|
|
143
|
+
from: @pagy.from,
|
|
144
|
+
to: @pagy.to,
|
|
145
|
+
in: @pagy.in,
|
|
146
|
+
previous: @pagy.previous,
|
|
147
|
+
next: @pagy.next
|
|
148
|
+
}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Base scope with store and ability
|
|
152
|
+
# When @parent is set (nested resources), uses parent association instead
|
|
153
|
+
def scope
|
|
154
|
+
base_scope = if @parent.present?
|
|
155
|
+
@parent.send(parent_association)
|
|
156
|
+
else
|
|
157
|
+
model_class.for_store(current_store)
|
|
158
|
+
end
|
|
159
|
+
base_scope = base_scope.accessible_by(current_ability, :show) unless @parent.present?
|
|
160
|
+
base_scope = base_scope.includes(scope_includes) if scope_includes.any?
|
|
161
|
+
base_scope = base_scope.preload_associations_lazily
|
|
162
|
+
model_class.include?(Spree::TranslatableResource) ? base_scope.i18n : base_scope
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Override to specify the association name on @parent
|
|
166
|
+
# Defaults to controller_name (e.g., 'wished_items' for WishlistItemsController)
|
|
167
|
+
def parent_association
|
|
168
|
+
controller_name
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Override in subclass to eager load associations that don't work well
|
|
172
|
+
# with ar_lazy_preload (e.g., prices, stock_items)
|
|
173
|
+
def scope_includes
|
|
174
|
+
[]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Override in subclass to define the model
|
|
178
|
+
def model_class
|
|
179
|
+
raise NotImplementedError, 'Subclass must implement model_class'
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Override in subclass to define the serializer class
|
|
183
|
+
def serializer_class
|
|
184
|
+
raise NotImplementedError, 'Subclass must implement serializer_class'
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Permit flat parameters based on model class
|
|
188
|
+
# Automatically infers attribute list from Spree::PermittedAttributes
|
|
189
|
+
# e.g., ProductsController -> Spree::PermittedAttributes.product_attributes
|
|
190
|
+
#
|
|
191
|
+
# Override in subclass for custom parameter handling
|
|
192
|
+
def permitted_params
|
|
193
|
+
params.permit(permitted_attributes)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Returns the permitted attributes list for the model
|
|
197
|
+
# Override in subclass for custom attributes
|
|
198
|
+
def permitted_attributes
|
|
199
|
+
Spree::PermittedAttributes.public_send(permitted_attributes_key)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Infers the PermittedAttributes key from model class
|
|
203
|
+
# e.g., Spree::Product -> :product_attributes
|
|
204
|
+
def permitted_attributes_key
|
|
205
|
+
:"#{model_class.model_name.element}_attributes"
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|