big_commerce-management_api 0.0.1
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 +7 -0
- data/.env.test.example +3 -0
- data/.github/workflows/ci.yml +24 -0
- data/.gitignore +62 -0
- data/.rspec +3 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +89 -0
- data/Rakefile +6 -0
- data/big_commerce-management_api.gemspec +33 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/etc/customers.csv +6 -0
- data/lib/big_commerce/management_api/classes.json +130 -0
- data/lib/big_commerce/management_api/classes.rb +32 -0
- data/lib/big_commerce/management_api/customers.rb +187 -0
- data/lib/big_commerce/management_api/endpoint.rb +294 -0
- data/lib/big_commerce/management_api/inventories.rb +34 -0
- data/lib/big_commerce/management_api/segments.rb +43 -0
- data/lib/big_commerce/management_api/subscribers.rb +70 -0
- data/lib/big_commerce/management_api/version.rb +7 -0
- data/lib/big_commerce/management_api.rb +25 -0
- metadata +124 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 633a92516ac21a7df777b1bdae97d4b0ec623f00f0946b77822bf04432cde707
|
|
4
|
+
data.tar.gz: 3409875235a0efe188b7a9f16fe22040600546dd68a5fe7ed739547934a4fb9c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fa94744067607cd0e15129a0815c2a45465ddbdd3b3dece4adb637494758b250d77febac896b23d5431db258843edb613b389743471f15bb6c2ed4939a27f5a9
|
|
7
|
+
data.tar.gz: fec8d7979001e9193e76d10c0231be65ec84312828969fd76a649beb453bf7fc49633c9332b4e9f454ae32d49c82ac58bb65a1c75336e2bd703ef35b25a69793
|
data/.env.test.example
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
- push
|
|
5
|
+
- pull_request
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
env:
|
|
11
|
+
BC_ACCESS_TOKEN: "Foo"
|
|
12
|
+
BC_STORE_HASH: "Bar"
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
ruby: ['3.2', '3.1', '3.0', '2.7', '2.6', '2.5']
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v3
|
|
19
|
+
- uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
|
|
24
|
+
- run: bundle exec rake
|
data/.gitignore
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Created by https://www.toptal.com/developers/gitignore/api/ruby
|
|
2
|
+
# Edit at https://www.toptal.com/developers/gitignore?templates=ruby
|
|
3
|
+
|
|
4
|
+
### Ruby ###
|
|
5
|
+
*.gem
|
|
6
|
+
*.rbc
|
|
7
|
+
/.config
|
|
8
|
+
/coverage/
|
|
9
|
+
/InstalledFiles
|
|
10
|
+
/pkg/
|
|
11
|
+
/spec/reports/
|
|
12
|
+
/spec/examples.txt
|
|
13
|
+
/test/tmp/
|
|
14
|
+
/test/version_tmp/
|
|
15
|
+
/tmp/
|
|
16
|
+
|
|
17
|
+
# Used by dotenv library to load environment variables.
|
|
18
|
+
.env*
|
|
19
|
+
!.env*.example
|
|
20
|
+
|
|
21
|
+
# Ignore Byebug command history file.
|
|
22
|
+
.byebug_history
|
|
23
|
+
|
|
24
|
+
## Specific to RubyMotion:
|
|
25
|
+
.dat*
|
|
26
|
+
.repl_history
|
|
27
|
+
build/
|
|
28
|
+
*.bridgesupport
|
|
29
|
+
build-iPhoneOS/
|
|
30
|
+
build-iPhoneSimulator/
|
|
31
|
+
|
|
32
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
33
|
+
#
|
|
34
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
35
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
36
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
37
|
+
# vendor/Pods/
|
|
38
|
+
|
|
39
|
+
## Documentation cache and generated files:
|
|
40
|
+
/.yardoc/
|
|
41
|
+
/_yardoc/
|
|
42
|
+
/doc/
|
|
43
|
+
/rdoc/
|
|
44
|
+
|
|
45
|
+
## Environment normalization:
|
|
46
|
+
/.bundle/
|
|
47
|
+
/vendor/bundle
|
|
48
|
+
/lib/bundler/man/
|
|
49
|
+
|
|
50
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
51
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
52
|
+
Gemfile.lock
|
|
53
|
+
.ruby-version
|
|
54
|
+
.ruby-gemset
|
|
55
|
+
|
|
56
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
57
|
+
.rvmrc
|
|
58
|
+
|
|
59
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
60
|
+
# .rubocop-https?--*
|
|
61
|
+
|
|
62
|
+
# End of https://www.toptal.com/developers/gitignore/api/ruby
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Skye Shaw
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# BigCommerce::ManagementAPI
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
v3 API client for [BigCommerce's REST Management API](https://developer.bigcommerce.com/docs/rest-management)
|
|
6
|
+
|
|
7
|
+
**Incomplete! v3 has many endpoints and this only provides what we need at ScreenStaring** which currently
|
|
8
|
+
is mostly customers and subscribers stuff but adding new endpoints should be trivial. See [Adding New Endpoints](#adding-new-endpoints).
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add this line to your application's `Gemfile`:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem "big_commerce-management_api"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
And then execute:
|
|
19
|
+
|
|
20
|
+
bundle install
|
|
21
|
+
|
|
22
|
+
Or install it yourself as:
|
|
23
|
+
|
|
24
|
+
gem install big_commerce-management_api
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```rb
|
|
29
|
+
require "big_commerce/management_api"
|
|
30
|
+
|
|
31
|
+
bc = BigCommerce::ManagementAPI.new(store_hash, auth_token)
|
|
32
|
+
customers = bc.customers.get
|
|
33
|
+
customers = bc.customers.get(:id => [1,2,3], :include => %w[addresses formfields], :page => 10, :limit => 25)
|
|
34
|
+
|
|
35
|
+
p customers.meta.pagination.total
|
|
36
|
+
p customers.headers.request_id
|
|
37
|
+
p customers.headers["some-header"]
|
|
38
|
+
|
|
39
|
+
# customers is Enumerable
|
|
40
|
+
customers.each do |customer|
|
|
41
|
+
p customer.first_name
|
|
42
|
+
p customer.addresses[0].address_type
|
|
43
|
+
# ...
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
customers = bc.customers.get(:page => 1, :size => 99)
|
|
48
|
+
rescue BigCommerce::ManagementAPI::ResponseError => e
|
|
49
|
+
p e.message
|
|
50
|
+
p e.headers.rate_limit_requests_left
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
attribute = bc.customers.attributes.create(
|
|
54
|
+
:name => "Daily screen-staring count",
|
|
55
|
+
:type => "number"
|
|
56
|
+
)
|
|
57
|
+
p attribute.id
|
|
58
|
+
p attribute.meta.total # 1
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Adding New Endpoints
|
|
62
|
+
|
|
63
|
+
1. Add JSON response body to `lib/big_commerce/management/classes.json`
|
|
64
|
+
1. Create or update `lib/big_commerce/management/THE_RESOURCE.rb`. See `customers.rb` for an example
|
|
65
|
+
1. For new classes
|
|
66
|
+
- If the response JSON's top-level property is not `"data"` define `RESULT_KEY` with the name of the top-level property
|
|
67
|
+
- Define `RESULT_INSTANCE` and set it to the class to use on response data pointed to by `RESULT_KEY`
|
|
68
|
+
- Call the appropriate HTTP verb method passing the endpoint's path (the portion **after** the API's `v3` URL) and parameters
|
|
69
|
+
1. If the method's return value should not be an `Array` call `unwrap(result)` before returning
|
|
70
|
+
|
|
71
|
+
## Testing
|
|
72
|
+
|
|
73
|
+
Tests use [VCR](https://github.com/vcr/vcr). If you need to re-record cassettes or create new ones a BigCommerce
|
|
74
|
+
account is with API access is required. See `.env.test.example`.
|
|
75
|
+
|
|
76
|
+
To re-record certain tests you must import fixture data into your store. See `etc/customers.csv`. These records can be deleted once
|
|
77
|
+
the VCR cassettes are recorded and you are done with development. The IDs they create are assumed by the tests which may present
|
|
78
|
+
a problem. Open an issue if so.
|
|
79
|
+
|
|
80
|
+
Any records that are created by the tests are deleted. Well, a delete is attempted in an `after` block, if something goes wrong with the test
|
|
81
|
+
the record(s) may remain in your store.
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
Made by [ScreenStaring](http://screenstaring.com)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require_relative 'lib/big_commerce/management_api/version'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "big_commerce-management_api"
|
|
5
|
+
spec.version = BigCommerce::ManagementAPI::VERSION
|
|
6
|
+
spec.authors = ["Skye Shaw"]
|
|
7
|
+
spec.email = ["skye.shaw@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = %q{v3 API client for BigCommerce's REST Management API}
|
|
10
|
+
spec.description = %q{v3 API client for BigCommerce's REST Management API. Implementation is far from complete but adding support for new endpoints is trivial.}
|
|
11
|
+
spec.homepage = "https://github.com/ScreenStaring/big_commerce-management_api"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
|
14
|
+
|
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/ScreenStaring/big_commerce-management_api"
|
|
17
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/ScreenStaring/big_commerce-management_api/issues"
|
|
18
|
+
# spec.metadata["changelog_uri"] = "https://github.com/ScreenStaring/big_commerce-management_api/blob/master/Changes"
|
|
19
|
+
|
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
22
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
24
|
+
end
|
|
25
|
+
spec.bindir = "exe"
|
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
spec.add_dependency "class2", ">= 0.6.0"
|
|
30
|
+
spec.add_development_dependency "vcr"
|
|
31
|
+
spec.add_development_dependency "webmock"
|
|
32
|
+
spec.add_development_dependency "dotenv"
|
|
33
|
+
end
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "big_commerce/management_api"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/etc/customers.csv
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Email Address,First Name,Last Name,Company,Phone,Notes,Store Credit,Customer Group,Address ID - 1,Address First Name - 1,Address Last Name - 1,Address Company - 1,Address Line 1 - 1,Address Line 2 - 1,Address City - 1,Address State - 1,Address Zip - 1,Address Country - 1,Receive Review/Abandoned Cart Emails?
|
|
2
|
+
user1@example.com,John,Doe,Acme Inc. ,555-555-1212,Note 1,59.99,,,,,Fofiha,59 West 46th Street,,New York,New York,10005,United States,N
|
|
3
|
+
user2@example.com,Bob,John,Acme Inc. ,212-555-1212,,,,,,,,123 55th St. ,#1,New York,New York,10038,United States,N
|
|
4
|
+
user3@example.com,Richard,Smith,FooBar LLC,310-555-1212,,101,,,Abe,Simpson,,21 W. 21st St. ,,New York,New York,10015,United States,Y
|
|
5
|
+
user4@example.com,Paulo,Costa,,,,,,,,,,666 6th Ave. ,,New York,New York,10005,United States,N
|
|
6
|
+
user5@example.com,Caio,Oliver ,,510-555-1212,,,,,,,Fofiha,125 55th St. ,Apt 3Q,New York,New York,10001,United States,Y
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"attribute": {
|
|
3
|
+
"id": 1,
|
|
4
|
+
"name": "Age",
|
|
5
|
+
"type": "string",
|
|
6
|
+
"date_modified": {"json_class":"Time","s":0,"n":0},
|
|
7
|
+
"date_created": {"json_class":"Time","s":0,"n":0}
|
|
8
|
+
},
|
|
9
|
+
"attribute_value": {
|
|
10
|
+
"attribute_id": 0,
|
|
11
|
+
"attribute_value": "string",
|
|
12
|
+
"id": 0,
|
|
13
|
+
"customer_id": 0,
|
|
14
|
+
"date_modified": {"json_class":"Time","s":0,"n":0},
|
|
15
|
+
"date_created": {"json_class":"Time","s":0,"n":0}
|
|
16
|
+
},
|
|
17
|
+
"customer": {
|
|
18
|
+
"id": 1,
|
|
19
|
+
"email": "string@example.com",
|
|
20
|
+
"first_name": "string",
|
|
21
|
+
"last_name": "string",
|
|
22
|
+
"company": "string",
|
|
23
|
+
"phone": "string",
|
|
24
|
+
"notes": "string",
|
|
25
|
+
"tax_exempt_category": "string",
|
|
26
|
+
"customer_group_id": 0,
|
|
27
|
+
"addresses": [
|
|
28
|
+
{
|
|
29
|
+
"first_name": "string",
|
|
30
|
+
"last_name": "string",
|
|
31
|
+
"company": "string",
|
|
32
|
+
"address1": "Addr1",
|
|
33
|
+
"address2": "",
|
|
34
|
+
"city": "string",
|
|
35
|
+
"state_or_province": "string",
|
|
36
|
+
"postal_code": "string",
|
|
37
|
+
"country_code": "st",
|
|
38
|
+
"phone": "string",
|
|
39
|
+
"address_type": "residential",
|
|
40
|
+
"customer_id": 0,
|
|
41
|
+
"id": 0,
|
|
42
|
+
"country": "string"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"store_credit_amounts": [
|
|
46
|
+
{
|
|
47
|
+
"amount": 43.15
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"form_fields": [
|
|
51
|
+
{ "name": "string", "value": "string" }
|
|
52
|
+
],
|
|
53
|
+
"accepts_product_review_abandoned_cart_emails": true,
|
|
54
|
+
"channel_ids": [],
|
|
55
|
+
"shopper_profile_id": "82511e54-4040-40fe-b742-2b25655f205b",
|
|
56
|
+
"segment_ids": [],
|
|
57
|
+
"date_modified": {"json_class":"Time","s":0,"n":0},
|
|
58
|
+
"date_created": {"json_class":"Time","s":0,"n":0}
|
|
59
|
+
},
|
|
60
|
+
"metafield": {
|
|
61
|
+
"id": 0,
|
|
62
|
+
"owner_client_id": "X123",
|
|
63
|
+
"key": "Staff Name",
|
|
64
|
+
"value": "Ronaldo",
|
|
65
|
+
"namespace": "Sales Department",
|
|
66
|
+
"permission_set": "app_only",
|
|
67
|
+
"resource_type": "cart",
|
|
68
|
+
"resource_id": 1,
|
|
69
|
+
"description": "order",
|
|
70
|
+
"date_modified": {"json_class":"Time","s":0,"n":0},
|
|
71
|
+
"date_created": {"json_class":"Time","s":0,"n":0}
|
|
72
|
+
},
|
|
73
|
+
"inventory": {
|
|
74
|
+
"identity": {
|
|
75
|
+
"sku": "RE-130",
|
|
76
|
+
"variant_id": 79,
|
|
77
|
+
"product_id": 120,
|
|
78
|
+
"sku_id": 0
|
|
79
|
+
},
|
|
80
|
+
"locations": [
|
|
81
|
+
{
|
|
82
|
+
"location_id": 1,
|
|
83
|
+
"location_code": "BC-LOCATION-1",
|
|
84
|
+
"location_name": "Default location",
|
|
85
|
+
"available_to_sell": 10,
|
|
86
|
+
"total_inventory_onhand": 11,
|
|
87
|
+
"location_enabled": true,
|
|
88
|
+
"settings": {
|
|
89
|
+
"safety_stock": 1,
|
|
90
|
+
"is_in_stock": true,
|
|
91
|
+
"warning_level": 1,
|
|
92
|
+
"bin_picking_number": "1"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
"segment": {
|
|
98
|
+
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
|
99
|
+
"name": "My Segment",
|
|
100
|
+
"description": "Description",
|
|
101
|
+
"updated_at": {"json_class":"Time","s":0,"n":0},
|
|
102
|
+
"created_at": {"json_class":"Time","s":0,"n":0}
|
|
103
|
+
},
|
|
104
|
+
"subscriber": {
|
|
105
|
+
"email": "string",
|
|
106
|
+
"first_name": "string",
|
|
107
|
+
"last_name": "string",
|
|
108
|
+
"source": "string",
|
|
109
|
+
"order_id": 1,
|
|
110
|
+
"channel_id": 1,
|
|
111
|
+
"id": 0,
|
|
112
|
+
"date_modified": {"json_class":"Time","s":0,"n":0},
|
|
113
|
+
"date_created": {"json_class":"Time","s":0,"n":0},
|
|
114
|
+
"consents": []
|
|
115
|
+
},
|
|
116
|
+
"meta": {
|
|
117
|
+
"pagination": {
|
|
118
|
+
"total": 246,
|
|
119
|
+
"count": 5,
|
|
120
|
+
"per_page": 5,
|
|
121
|
+
"current_page": 1,
|
|
122
|
+
"total_pages": 50,
|
|
123
|
+
"links": {
|
|
124
|
+
"previous": "?limit=5&page=2",
|
|
125
|
+
"current": "?limit=5&page=3",
|
|
126
|
+
"next": "?limit=5&page=4"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "class2"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
# This results in certain properties in the JSON samples/definitions to be parsed as
|
|
7
|
+
# Time which class2 will see and convert the attribute values to Time
|
|
8
|
+
require "json/add/time"
|
|
9
|
+
|
|
10
|
+
classes = File.read(File.join(__dir__, "classes.json"))
|
|
11
|
+
class2 "BigCommerce::ManagementAPI", JSON.parse(classes, :create_additions => true) do
|
|
12
|
+
def meta
|
|
13
|
+
@meta
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def meta=(meta)
|
|
17
|
+
@meta = meta
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def headers
|
|
21
|
+
@headers
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def headers=(headers)
|
|
25
|
+
@headers = headers
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
require "big_commerce/management_api/customers"
|
|
30
|
+
require "big_commerce/management_api/inventories"
|
|
31
|
+
require "big_commerce/management_api/segments"
|
|
32
|
+
require "big_commerce/management_api/subscribers"
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "big_commerce/management_api/endpoint"
|
|
4
|
+
|
|
5
|
+
module BigCommerce
|
|
6
|
+
module ManagementAPI
|
|
7
|
+
class Customers < Endpoint
|
|
8
|
+
class Addresses < Endpoint
|
|
9
|
+
PATH = "customers/addresses"
|
|
10
|
+
RESULT_INSTANCE = Address
|
|
11
|
+
|
|
12
|
+
def create(*attributes)
|
|
13
|
+
attributes.flatten!
|
|
14
|
+
|
|
15
|
+
POST(PATH, attributes.map(&:to_h))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def delete(*ids)
|
|
19
|
+
ids.flatten!
|
|
20
|
+
|
|
21
|
+
DELETE(
|
|
22
|
+
PATH,
|
|
23
|
+
with_in_param({:id => ids}, :id)
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get(options = {})
|
|
28
|
+
GET(
|
|
29
|
+
PATH,
|
|
30
|
+
with_in_param(
|
|
31
|
+
options,
|
|
32
|
+
:company,
|
|
33
|
+
:customer_id,
|
|
34
|
+
:id,
|
|
35
|
+
:name
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Attributes < Endpoint
|
|
42
|
+
PATH = "customers/attributes"
|
|
43
|
+
RESULT_INSTANCE = Attribute
|
|
44
|
+
|
|
45
|
+
def get(options = {})
|
|
46
|
+
GET(PATH, options)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create(*attributes)
|
|
50
|
+
attributes.flatten!
|
|
51
|
+
|
|
52
|
+
POST(PATH, attributes.map(&:to_h))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def delete(*ids)
|
|
56
|
+
ids.flatten!
|
|
57
|
+
|
|
58
|
+
DELETE(
|
|
59
|
+
PATH,
|
|
60
|
+
with_in_param({:id => ids}, :id)
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class AttributeValues < Endpoint
|
|
66
|
+
PATH = "customers/attribute-values"
|
|
67
|
+
RESULT_INSTANCE = AttributeValue
|
|
68
|
+
|
|
69
|
+
def get(options = {})
|
|
70
|
+
GET(
|
|
71
|
+
PATH,
|
|
72
|
+
with_in_param(
|
|
73
|
+
options,
|
|
74
|
+
:attribute_id,
|
|
75
|
+
:customer_id
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def upsert(*attributes)
|
|
81
|
+
attributes.flatten!
|
|
82
|
+
|
|
83
|
+
PUT(PATH, attributes)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Metafields < Endpoint
|
|
88
|
+
PATH = "customers/%d/metafields"
|
|
89
|
+
RESULT_INSTANCE = Metafield
|
|
90
|
+
|
|
91
|
+
def get(customer_id, options = {})
|
|
92
|
+
GET(path(customer_id), options)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def create(metafield)
|
|
96
|
+
metafield = metafield.to_h
|
|
97
|
+
id = metafield.delete(:resource_id)
|
|
98
|
+
|
|
99
|
+
if id.nil?
|
|
100
|
+
raise ArgumentError, "Cannot create customer metafield: given metafield record has no resource_id"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
POST(path(id), metafield)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def update(metafield)
|
|
107
|
+
metafield = metafield.to_h
|
|
108
|
+
|
|
109
|
+
resource = metafield.delete(:resource_id)
|
|
110
|
+
if resource.nil?
|
|
111
|
+
raise ArgumentError, "Cannot update customer metafield: given metafield has no resource_id"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
id = metafield.delete(:id)
|
|
115
|
+
if id.nil?
|
|
116
|
+
raise ArgumentError, "Cannot update customer metafield: given metafield has no id"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
result = PUT(path(resource_id, id), metafield)
|
|
120
|
+
unwrap(result)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
def path(customer_id, *rest)
|
|
126
|
+
path = sprintf(PATH, customer_id)
|
|
127
|
+
return path if rest.empty?
|
|
128
|
+
|
|
129
|
+
path << "/" << rest.join("/")
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
PATH = "customers"
|
|
134
|
+
RESULT_INSTANCE = Customer
|
|
135
|
+
|
|
136
|
+
attr_reader :addresses,
|
|
137
|
+
:attributes,
|
|
138
|
+
:attribute_values,
|
|
139
|
+
:metafields
|
|
140
|
+
|
|
141
|
+
def initialize(*argz)
|
|
142
|
+
super(*argz)
|
|
143
|
+
|
|
144
|
+
@addresses = Addresses.new(*argz)
|
|
145
|
+
@attributes = Attributes.new(*argz)
|
|
146
|
+
@attribute_values = AttributeValues.new(*argz)
|
|
147
|
+
@metafields = Metafields.new(*argz)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def create(*customers)
|
|
151
|
+
customers.flatten!
|
|
152
|
+
|
|
153
|
+
POST(PATH, customers.map(&:to_h))
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def delete(*ids)
|
|
157
|
+
ids.flatten!
|
|
158
|
+
|
|
159
|
+
DELETE(
|
|
160
|
+
PATH,
|
|
161
|
+
with_in_param({:id => ids}, :id)
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def get(options = {})
|
|
166
|
+
GET(
|
|
167
|
+
PATH,
|
|
168
|
+
with_in_param(
|
|
169
|
+
options,
|
|
170
|
+
:company,
|
|
171
|
+
:customer_group_id,
|
|
172
|
+
:email,
|
|
173
|
+
:id,
|
|
174
|
+
:name,
|
|
175
|
+
:registration_ip_address
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def update(*customers)
|
|
181
|
+
customers.flatten!
|
|
182
|
+
|
|
183
|
+
PUT(PATH, customers.map(&:to_h))
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "big_commerce/management_api/version"
|
|
6
|
+
|
|
7
|
+
module BigCommerce
|
|
8
|
+
module ManagementAPI
|
|
9
|
+
Error = Class.new(StandardError)
|
|
10
|
+
|
|
11
|
+
class ResponseHeaders
|
|
12
|
+
def initialize(headers)
|
|
13
|
+
@headers = headers || {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def [](name)
|
|
17
|
+
@headers[name]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def request_id
|
|
21
|
+
value = @headers["x-request-id"]
|
|
22
|
+
value.is_a?(Array) ? value[0] : value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
%w[x-rate-limit-requests-left
|
|
26
|
+
x-rate-limit-time-reset-ms
|
|
27
|
+
x-rate-limit-requests-quota
|
|
28
|
+
x-rate-limit-time-window-ms].each do |header|
|
|
29
|
+
|
|
30
|
+
method = header.delete_prefix("x-")
|
|
31
|
+
method.tr!("-", "_")
|
|
32
|
+
|
|
33
|
+
define_method(method) do
|
|
34
|
+
value = @headers[header]
|
|
35
|
+
# Net::HTTP returns as an array
|
|
36
|
+
(value.is_a?(Array) ? value[0] : value).to_i
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class ResponseError < Error
|
|
42
|
+
attr_reader :headers
|
|
43
|
+
|
|
44
|
+
def initialize(data, headers)
|
|
45
|
+
@headers = ResponseHeaders.new(headers)
|
|
46
|
+
@data = data
|
|
47
|
+
|
|
48
|
+
super error_message(data)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def error_message(data)
|
|
54
|
+
#
|
|
55
|
+
# Looks for a structure like one of these and picks best message:
|
|
56
|
+
#
|
|
57
|
+
# A:
|
|
58
|
+
#
|
|
59
|
+
# {"errors"=>
|
|
60
|
+
# [{"status"=>409,
|
|
61
|
+
# "title"=>"Cannot have multiple segments with the same name",
|
|
62
|
+
# "type"=>
|
|
63
|
+
# "https://developer.bigcommerce.com/api-docs/getting-started/api-status-codes",
|
|
64
|
+
# "errors"=>{}}]
|
|
65
|
+
#
|
|
66
|
+
#
|
|
67
|
+
# B:
|
|
68
|
+
#
|
|
69
|
+
# {"status"=>422,
|
|
70
|
+
# "title"=>"Set customer attribute values failed.",
|
|
71
|
+
# "type"=>
|
|
72
|
+
# "https://developer.bigcommerce.com/api-docs/getting-started/api-status-codes",
|
|
73
|
+
# "errors"=>{"0.data"=>"missing attribute value"}}
|
|
74
|
+
#
|
|
75
|
+
return data unless data.is_a?(Hash)
|
|
76
|
+
|
|
77
|
+
data = data["errors"][0] if data["errors"].is_a?(Array)
|
|
78
|
+
|
|
79
|
+
if data["errors"].any?
|
|
80
|
+
errors = data["errors"].map { |property, message| "#{property}: #{message.chomp(".")}" }
|
|
81
|
+
errors.join(", ")
|
|
82
|
+
else
|
|
83
|
+
title = data["title"].chomp(".")
|
|
84
|
+
sprintf("%s (%s)", title, data["status"])
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class Endpoint
|
|
90
|
+
HOST = "api.bigcommerce.com"
|
|
91
|
+
PORT = 443
|
|
92
|
+
|
|
93
|
+
USER_AGENT = "BigCommerce Management API Client v#{BigCommerce::ManagementAPI::VERSION} (Ruby v#{RUBY_VERSION})"
|
|
94
|
+
|
|
95
|
+
CONTENT_TYPE = "Content-Type"
|
|
96
|
+
CONTENT_TYPE_JSON = "application/json"
|
|
97
|
+
|
|
98
|
+
JSON_CONTENT_TYPES = [CONTENT_TYPE_JSON, "application/problem+json"].freeze
|
|
99
|
+
|
|
100
|
+
RESULT_KEY = "data"
|
|
101
|
+
|
|
102
|
+
# May go in its own file
|
|
103
|
+
class Response
|
|
104
|
+
include Enumerable
|
|
105
|
+
|
|
106
|
+
# class Pagination
|
|
107
|
+
class2 self,
|
|
108
|
+
:pagination => {
|
|
109
|
+
:total => 0,
|
|
110
|
+
:count => 0,
|
|
111
|
+
:per_page => 0,
|
|
112
|
+
:current_page => 0,
|
|
113
|
+
:total_pages => 0,
|
|
114
|
+
:links => {
|
|
115
|
+
:previous => "string",
|
|
116
|
+
:current => "string",
|
|
117
|
+
:next => "string"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
class Meta
|
|
122
|
+
attr_reader :pagination, :total, :success, :failed
|
|
123
|
+
|
|
124
|
+
def initialize(meta)
|
|
125
|
+
@total = meta["total"]
|
|
126
|
+
@success = meta["success"]
|
|
127
|
+
@failed = meta["failed"]
|
|
128
|
+
|
|
129
|
+
@pagination = Pagination.new(meta["pagination"]) if meta["pagination"]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
attr_reader :meta, :headers
|
|
134
|
+
|
|
135
|
+
def initialize(headers, result = nil, meta = nil)
|
|
136
|
+
@result = result || []
|
|
137
|
+
@headers = ResponseHeaders.new(headers)
|
|
138
|
+
@meta = Meta.new(meta) if meta
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def each(&block)
|
|
142
|
+
@result.each(&block)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def initialize(store_hash, auth_token, options = nil)
|
|
147
|
+
raise ArgumentError, "store hash required" if store_hash.to_s.empty?
|
|
148
|
+
raise ArgumentError, "auth token required" if auth_token.to_s.empty?
|
|
149
|
+
|
|
150
|
+
@store_hash = store_hash
|
|
151
|
+
@auth_token = auth_token
|
|
152
|
+
@options = options || {}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
protected
|
|
156
|
+
|
|
157
|
+
def DELETE(path, data = {})
|
|
158
|
+
path = endpoint(path)
|
|
159
|
+
path << query_string(data) if data && data.any?
|
|
160
|
+
|
|
161
|
+
request(Net::HTTP::Delete.new(path), data)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def GET(path, data = {})
|
|
165
|
+
path = endpoint(path)
|
|
166
|
+
path << query_string(data) if data && data.any?
|
|
167
|
+
|
|
168
|
+
request(Net::HTTP::Get.new(path), data)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def POST(path, data = {})
|
|
172
|
+
request(Net::HTTP::Post.new(endpoint(path)), data)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def PUT(path, data = {})
|
|
176
|
+
request(Net::HTTP::Put.new(endpoint(path)), data)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# For better or worse all Response instances contain an Array
|
|
180
|
+
# In some cases we don't want this since response only contains a single result
|
|
181
|
+
def unwrap(result)
|
|
182
|
+
record = result.first
|
|
183
|
+
return unless record
|
|
184
|
+
|
|
185
|
+
record.meta = result.meta
|
|
186
|
+
record.headers = result.headers
|
|
187
|
+
record
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def with_in_param(options, *param_names)
|
|
191
|
+
return unless options
|
|
192
|
+
|
|
193
|
+
options = options.dup
|
|
194
|
+
options.keys.each do |name|
|
|
195
|
+
# Remove optional ":in" portion from "id:in" which may or may not be a Symbol
|
|
196
|
+
name = name.to_s.split(":")[0].to_sym
|
|
197
|
+
next unless param_names.include?(name)
|
|
198
|
+
|
|
199
|
+
values = Array(options.delete(name))
|
|
200
|
+
|
|
201
|
+
in_name = "#{name}:in"
|
|
202
|
+
values.concat(Array(options.delete(in_name)))
|
|
203
|
+
|
|
204
|
+
next unless values.any?
|
|
205
|
+
|
|
206
|
+
options[in_name] = values
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
options
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def query_string(params)
|
|
215
|
+
query = []
|
|
216
|
+
|
|
217
|
+
# We do this manually to join arrays and because time cannot be escaped as it will not be properly applied server-side
|
|
218
|
+
params.each do |name, value|
|
|
219
|
+
name = URI.encode_www_form_component(name)
|
|
220
|
+
|
|
221
|
+
if value.is_a?(Array)
|
|
222
|
+
value = value.join(",")
|
|
223
|
+
elsif value.respond_to?(:strftime)
|
|
224
|
+
value = value.strftime("%Y-%m-%dT%H:%M:%S%z")
|
|
225
|
+
else
|
|
226
|
+
value = URI.encode_www_form_component(value)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
query << "#{name}=#{value}"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
sprintf("?%s", query.join("&"))
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def endpoint(path)
|
|
236
|
+
sprintf("/stores/%s/v3/%s", @store_hash, path)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# TODO: move this to request() so we can create ResponseError
|
|
240
|
+
def parse_json(s)
|
|
241
|
+
JSON.parse(s)
|
|
242
|
+
rescue JSON::ParserError => e
|
|
243
|
+
raise Error, "failed to parse response JSON: #{e}"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def request(req, data = {})
|
|
247
|
+
req["X-Auth-Token"] = @auth_token
|
|
248
|
+
req["User-Agent"] = USER_AGENT
|
|
249
|
+
|
|
250
|
+
if req.request_body_permitted? && data && data.any?
|
|
251
|
+
req.body = data.to_json
|
|
252
|
+
req[CONTENT_TYPE] = CONTENT_TYPE_JSON
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
request = Net::HTTP.new(HOST, PORT)
|
|
256
|
+
request.use_ssl = true
|
|
257
|
+
|
|
258
|
+
if !@options[:debug]
|
|
259
|
+
request.set_debug_output(nil)
|
|
260
|
+
else
|
|
261
|
+
request.set_debug_output(
|
|
262
|
+
@options[:debug].is_a?(IO) ? @options[:debug] : $stderr
|
|
263
|
+
)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
request.start { |http| handle_response(http.request(req)) }
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def handle_response(res)
|
|
270
|
+
# TODO: data can be HTML string! Don't want this in the error! Do we?
|
|
271
|
+
data = res.body && JSON_CONTENT_TYPES.include?(res[CONTENT_TYPE]) ? parse_json(res.body) : res.body
|
|
272
|
+
# pp data
|
|
273
|
+
# Otherwise only available by name via #[]
|
|
274
|
+
headers = res.to_hash
|
|
275
|
+
|
|
276
|
+
raise ResponseError.new(data, headers) if res.code[0] != "2"
|
|
277
|
+
|
|
278
|
+
# 204, likely
|
|
279
|
+
return Response.new(headers) unless data
|
|
280
|
+
|
|
281
|
+
result = data[self.class::RESULT_KEY]
|
|
282
|
+
if result.is_a?(Array)
|
|
283
|
+
result.map! { |data| self.class::RESULT_INSTANCE.new(data) }
|
|
284
|
+
else
|
|
285
|
+
result = [self.class::RESULT_INSTANCE.new(result)]
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# If response code is 2XX and data is a String we will have an error here
|
|
289
|
+
# but it's TBD if this is ever the case
|
|
290
|
+
Response.new(headers, result, data["meta"])
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "big_commerce/management_api/endpoint"
|
|
4
|
+
|
|
5
|
+
module BigCommerce
|
|
6
|
+
module ManagementAPI
|
|
7
|
+
class Inventories
|
|
8
|
+
class Items < Endpoint
|
|
9
|
+
PATH = "inventory/items"
|
|
10
|
+
RESULT_INSTANCE = Inventory
|
|
11
|
+
|
|
12
|
+
def get(options = {})
|
|
13
|
+
GET(
|
|
14
|
+
PATH,
|
|
15
|
+
with_in_param(
|
|
16
|
+
options,
|
|
17
|
+
:location_code,
|
|
18
|
+
:location_id,
|
|
19
|
+
:product_id,
|
|
20
|
+
:sku,
|
|
21
|
+
:variant_id
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attr_reader :items
|
|
28
|
+
|
|
29
|
+
def initialize(*argz)
|
|
30
|
+
@items = Items.new(*argz)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "big_commerce/management_api/endpoint"
|
|
4
|
+
|
|
5
|
+
module BigCommerce
|
|
6
|
+
module ManagementAPI
|
|
7
|
+
class Segments < Endpoint
|
|
8
|
+
PATH = "segments"
|
|
9
|
+
RESULT_INSTANCE = Segment
|
|
10
|
+
|
|
11
|
+
def create(*segments)
|
|
12
|
+
segments.flatten!
|
|
13
|
+
|
|
14
|
+
POST(PATH, segments.map(&:to_h))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def delete(*ids)
|
|
18
|
+
ids.flatten!
|
|
19
|
+
|
|
20
|
+
DELETE(
|
|
21
|
+
PATH,
|
|
22
|
+
with_in_param({:id => ids}, :id)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get(options = {})
|
|
27
|
+
GET(
|
|
28
|
+
PATH,
|
|
29
|
+
with_in_param(
|
|
30
|
+
options,
|
|
31
|
+
:id
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update(*segments)
|
|
37
|
+
segments.flatten!
|
|
38
|
+
|
|
39
|
+
PUT(PATH, segments.map(&:to_h))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "big_commerce/management_api/endpoint"
|
|
4
|
+
|
|
5
|
+
module BigCommerce
|
|
6
|
+
module ManagementAPI
|
|
7
|
+
class Subscribers < Endpoint
|
|
8
|
+
PATH = "customers/subscribers"
|
|
9
|
+
RESULT_INSTANCE = Subscriber
|
|
10
|
+
|
|
11
|
+
def create(attributes)
|
|
12
|
+
result = POST(PATH, attributes)
|
|
13
|
+
unwrap(result)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def delete(options)
|
|
17
|
+
DELETE(
|
|
18
|
+
PATH,
|
|
19
|
+
with_in_param(
|
|
20
|
+
options,
|
|
21
|
+
:date_created,
|
|
22
|
+
:date_modified,
|
|
23
|
+
:email,
|
|
24
|
+
:first_name,
|
|
25
|
+
:id,
|
|
26
|
+
:last_name,
|
|
27
|
+
:order_id,
|
|
28
|
+
:source
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
#
|
|
35
|
+
# Given an ID find a single Subscriber. Given a Hash find Subscribers by the provided criteria.
|
|
36
|
+
#
|
|
37
|
+
def get(options_or_id)
|
|
38
|
+
query = options_or_id
|
|
39
|
+
|
|
40
|
+
if query.is_a?(Hash)
|
|
41
|
+
query = with_in_param(
|
|
42
|
+
query,
|
|
43
|
+
:date_created,
|
|
44
|
+
:date_modified,
|
|
45
|
+
:email,
|
|
46
|
+
:first_name,
|
|
47
|
+
:id,
|
|
48
|
+
:last_name,
|
|
49
|
+
:order_id,
|
|
50
|
+
:source
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
GET(PATH, query)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def update(attributes)
|
|
58
|
+
attributes = attributes.to_h
|
|
59
|
+
|
|
60
|
+
id = attributes.delete(:id)
|
|
61
|
+
if id.nil?
|
|
62
|
+
raise ArgumentError, "Cannot update subscriber: given subscriber has no id"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
result = UPDATE("#{PATH}/#{id}", attributes)
|
|
66
|
+
unwrap(result)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "big_commerce/management_api/classes"
|
|
4
|
+
|
|
5
|
+
module BigCommerce
|
|
6
|
+
module ManagementAPI
|
|
7
|
+
def self.new(*argz)
|
|
8
|
+
Client.new(*argz)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Client
|
|
12
|
+
attr_reader :customers,
|
|
13
|
+
:inventories,
|
|
14
|
+
:segments,
|
|
15
|
+
:subscribers
|
|
16
|
+
|
|
17
|
+
def initialize(*argz)
|
|
18
|
+
@customers = ManagementAPI::Customers.new(*argz)
|
|
19
|
+
@inventories = ManagementAPI::Inventories.new(*argz)
|
|
20
|
+
@segments = ManagementAPI::Segments.new(*argz)
|
|
21
|
+
@subscribers = ManagementAPI::Subscribers.new(*argz)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: big_commerce-management_api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Skye Shaw
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-11-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: class2
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.6.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.6.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: vcr
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: webmock
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: dotenv
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
description: v3 API client for BigCommerce's REST Management API. Implementation is
|
|
70
|
+
far from complete but adding support for new endpoints is trivial.
|
|
71
|
+
email:
|
|
72
|
+
- skye.shaw@gmail.com
|
|
73
|
+
executables: []
|
|
74
|
+
extensions: []
|
|
75
|
+
extra_rdoc_files: []
|
|
76
|
+
files:
|
|
77
|
+
- ".env.test.example"
|
|
78
|
+
- ".github/workflows/ci.yml"
|
|
79
|
+
- ".gitignore"
|
|
80
|
+
- ".rspec"
|
|
81
|
+
- Gemfile
|
|
82
|
+
- LICENSE.txt
|
|
83
|
+
- README.md
|
|
84
|
+
- Rakefile
|
|
85
|
+
- big_commerce-management_api.gemspec
|
|
86
|
+
- bin/console
|
|
87
|
+
- bin/setup
|
|
88
|
+
- etc/customers.csv
|
|
89
|
+
- lib/big_commerce/management_api.rb
|
|
90
|
+
- lib/big_commerce/management_api/classes.json
|
|
91
|
+
- lib/big_commerce/management_api/classes.rb
|
|
92
|
+
- lib/big_commerce/management_api/customers.rb
|
|
93
|
+
- lib/big_commerce/management_api/endpoint.rb
|
|
94
|
+
- lib/big_commerce/management_api/inventories.rb
|
|
95
|
+
- lib/big_commerce/management_api/segments.rb
|
|
96
|
+
- lib/big_commerce/management_api/subscribers.rb
|
|
97
|
+
- lib/big_commerce/management_api/version.rb
|
|
98
|
+
homepage: https://github.com/ScreenStaring/big_commerce-management_api
|
|
99
|
+
licenses:
|
|
100
|
+
- MIT
|
|
101
|
+
metadata:
|
|
102
|
+
homepage_uri: https://github.com/ScreenStaring/big_commerce-management_api
|
|
103
|
+
source_code_uri: https://github.com/ScreenStaring/big_commerce-management_api
|
|
104
|
+
bug_tracker_uri: https://github.com/ScreenStaring/big_commerce-management_api/issues
|
|
105
|
+
post_install_message:
|
|
106
|
+
rdoc_options: []
|
|
107
|
+
require_paths:
|
|
108
|
+
- lib
|
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: 2.3.0
|
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '0'
|
|
119
|
+
requirements: []
|
|
120
|
+
rubygems_version: 3.1.6
|
|
121
|
+
signing_key:
|
|
122
|
+
specification_version: 4
|
|
123
|
+
summary: v3 API client for BigCommerce's REST Management API
|
|
124
|
+
test_files: []
|