From b316cc2da8a0983dc7916cfb6af833a828a1460d Mon Sep 17 00:00:00 2001 From: sshaw Date: Wed, 30 Oct 2024 22:43:24 -0400 Subject: [PATCH] Don't escape ISO 8601 time query string parameters API will not process them when escaped --- lib/big_commerce/management_api/endpoint.rb | 20 ++- ...customers_created_after_the_given_date.yml | 131 ++++++++++++++++++ spec/customers_spec.rb | 47 ++++++- 3 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 spec/cassettes/BigCommerce_ManagementAPI_Customers/_customers/_get/_date_created_min/returns_customers_created_after_the_given_date.yml diff --git a/lib/big_commerce/management_api/endpoint.rb b/lib/big_commerce/management_api/endpoint.rb index 47c313c..0954b65 100644 --- a/lib/big_commerce/management_api/endpoint.rb +++ b/lib/big_commerce/management_api/endpoint.rb @@ -203,7 +203,7 @@ def with_in_param(options, *param_names) next unless values.any? - options[in_name] = values.join(",") + options[in_name] = values end options @@ -212,18 +212,24 @@ def with_in_param(options, *param_names) private def query_string(params) - params = params.dup - params.keys.each do |name| - value = params[name] + query = [] + + # We do this manually to join arrays and because time cannot be escaped as it will not be properly applied server-side + params.each do |name, value| + name = URI.encode_www_form_component(name) if value.is_a?(Array) - params[name] = value.join(",") + value = value.join(",") elsif value.respond_to?(:strftime) - params[name] = value.strftime("%Y-%m-%dT%H:%M:%S%z") + value = value.strftime("%Y-%m-%dT%H:%M:%S%z") + else + value = URI.encode_www_form_component(value) end + + query << "#{name}=#{value}" end - sprintf("?%s", URI.encode_www_form(params)) + sprintf("?%s", query.join("&")) end def endpoint(path) diff --git a/spec/cassettes/BigCommerce_ManagementAPI_Customers/_customers/_get/_date_created_min/returns_customers_created_after_the_given_date.yml b/spec/cassettes/BigCommerce_ManagementAPI_Customers/_customers/_get/_date_created_min/returns_customers_created_after_the_given_date.yml new file mode 100644 index 0000000..867d16d --- /dev/null +++ b/spec/cassettes/BigCommerce_ManagementAPI_Customers/_customers/_get/_date_created_min/returns_customers_created_after_the_given_date.yml @@ -0,0 +1,131 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.bigcommerce.com/stores//v3/customers + body: + encoding: UTF-8 + string: '[{"email":"test.customers.created.at.min1@example.com","first_name":"John","last_name":"Doe"},{"email":"test.customers.created.at.min2@example.com","first_name":"Jane","last_name":"Doe"}]' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - BigCommerce Management API Client v0.0.1.pre1 (Ruby v2.7.8) + X-Auth-Token: + - "" + Content-Type: + - application/json + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + X-Rate-Limit-Requests-Left: + - '3748' + X-Rate-Limit-Time-Reset-Ms: + - '30000' + X-Rate-Limit-Requests-Quota: + - '3749' + X-Rate-Limit-Time-Window-Ms: + - '30000' + X-Request-Id: + - 5dec018217c57946a8315f5bd2afc4cc + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + body: + encoding: ASCII-8BIT + string: '{"data":[{"id":21,"authentication":{"force_password_reset":false},"company":"","customer_group_id":0,"email":"test.customers.created.at.min1@example.com","first_name":"John","last_name":"Doe","notes":"","phone":"","registration_ip_address":"","tax_exempt_category":"","date_created":"2024-10-31T02:30:39Z","date_modified":"2024-10-31T02:30:39Z","accepts_product_review_abandoned_cart_emails":false,"store_credit_amounts":[{"amount":0}],"origin_channel_id":1,"channel_ids":null},{"id":22,"authentication":{"force_password_reset":false},"company":"","customer_group_id":0,"email":"test.customers.created.at.min2@example.com","first_name":"Jane","last_name":"Doe","notes":"","phone":"","registration_ip_address":"","tax_exempt_category":"","date_created":"2024-10-31T02:30:39Z","date_modified":"2024-10-31T02:30:39Z","accepts_product_review_abandoned_cart_emails":false,"store_credit_amounts":[{"amount":0}],"origin_channel_id":1,"channel_ids":null}],"meta":{}}' + recorded_at: Thu, 31 Oct 2024 02:30:40 GMT +- request: + method: get + uri: https://api.bigcommerce.com/stores//v3/customers?date_created:min=2024-10-30T22:30:38-0400 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - BigCommerce Management API Client v0.0.1.pre1 (Ruby v2.7.8) + X-Auth-Token: + - "" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + X-Rate-Limit-Requests-Left: + - '3747' + X-Rate-Limit-Time-Reset-Ms: + - '28216' + X-Rate-Limit-Requests-Quota: + - '3749' + X-Rate-Limit-Time-Window-Ms: + - '30000' + X-Request-Id: + - 3ae52b9b570c8750d08ac798255bb410 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + body: + encoding: ASCII-8BIT + string: '{"data":[{"id":21,"authentication":{"force_password_reset":false},"company":"","customer_group_id":0,"email":"test.customers.created.at.min1@example.com","first_name":"John","last_name":"Doe","notes":"","phone":"","registration_ip_address":"","tax_exempt_category":"","date_created":"2024-10-31T02:30:39Z","date_modified":"2024-10-31T02:30:39Z","accepts_product_review_abandoned_cart_emails":false,"origin_channel_id":1,"channel_ids":null},{"id":22,"authentication":{"force_password_reset":false},"company":"","customer_group_id":0,"email":"test.customers.created.at.min2@example.com","first_name":"Jane","last_name":"Doe","notes":"","phone":"","registration_ip_address":"","tax_exempt_category":"","date_created":"2024-10-31T02:30:39Z","date_modified":"2024-10-31T02:30:39Z","accepts_product_review_abandoned_cart_emails":false,"origin_channel_id":1,"channel_ids":null}],"meta":{"pagination":{"total":2,"count":2,"per_page":50,"current_page":1,"total_pages":1}}}' + recorded_at: Thu, 31 Oct 2024 02:30:41 GMT +- request: + method: delete + uri: https://api.bigcommerce.com/stores//v3/customers?id:in=21,22 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - BigCommerce Management API Client v0.0.1.pre1 (Ruby v2.7.8) + X-Auth-Token: + - "" + response: + status: + code: 204 + message: No Content + headers: + Connection: + - keep-alive + X-Rate-Limit-Requests-Left: + - '3746' + X-Rate-Limit-Time-Reset-Ms: + - '26746' + X-Rate-Limit-Requests-Quota: + - '3749' + X-Rate-Limit-Time-Window-Ms: + - '30000' + X-Request-Id: + - 2bcc5e154e5990b3abc2aaa100fd177f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + body: + encoding: UTF-8 + string: '' + recorded_at: Thu, 31 Oct 2024 02:30:43 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/customers_spec.rb b/spec/customers_spec.rb index 4702f8d..4308853 100644 --- a/spec/customers_spec.rb +++ b/spec/customers_spec.rb @@ -1,12 +1,12 @@ RSpec.describe BigCommerce::ManagementAPI::Customers, :vcr do - describe "#customers" do - describe "#create" do - before { @created = [] } + before { @created = [] } - after do - client.customers.delete(*@created) if @created.any? - end + after do + client.customers.delete(*@created) if @created.any? + end + describe "#customers" do + describe "#create" do describe "creating a single customer" do it "returns the new customer" do result = client.customers.create( @@ -72,6 +72,41 @@ ) end + describe ":date_created:min" do + it "returns customers created after the given date" do + # This is the time the VCR cassette was recorded + # If test is re-recorded switch use Time.now first. Other ways to do this? + # Can't freeze time on API server! + + # after = Time.now + after = Time.parse("2024-10-30T22:30:38-0400") + result = client.customers.create( + { + :email => "test.customers.created.at.min1@example.com", + :first_name => "John", + :last_name => "Doe" + }, + { + :email => "test.customers.created.at.min2@example.com", + :first_name => "Jane", + :last_name => "Doe" + } + ) + + @created.concat(result.map(&:id)) + + result = client.customers.get("date_created:min" => after) + expect(result.count).to eq 2 + + customers = result.sort_by(&:email) + expect(customers[0]).to be_a(BigCommerce::ManagementAPI::Customer) + expect(customers[0].email).to eq "test.customers.created.at.min1@example.com" + + expect(customers[1]).to be_a(BigCommerce::ManagementAPI::Customer) + expect(customers[1].email).to eq "test.customers.created.at.min2@example.com" + end + end + describe ":id" do context "given a single ID" do it "returns the customer with the given ID" do