dato 0.5.1 → 0.6.0
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/Rakefile +0 -38
- data/lib/dato/account/client.rb +3 -70
- data/lib/dato/api_client.rb +98 -0
- data/lib/dato/json_api_serializer.rb +72 -17
- data/lib/dato/paginator.rb +33 -0
- data/lib/dato/repo.rb +91 -0
- data/lib/dato/site/client.rb +3 -91
- data/lib/dato/upload/file.rb +1 -1
- data/lib/dato/version.rb +1 -1
- metadata +5 -20
- data/lib/dato/account/repo/account.rb +0 -23
- data/lib/dato/account/repo/base.rb +0 -27
- data/lib/dato/account/repo/deploy_event.rb +0 -18
- data/lib/dato/account/repo/site.rb +0 -49
- data/lib/dato/site/paginator.rb +0 -35
- data/lib/dato/site/repo/access_token.rb +0 -47
- data/lib/dato/site/repo/base.rb +0 -27
- data/lib/dato/site/repo/deploy_event.rb +0 -18
- data/lib/dato/site/repo/field.rb +0 -41
- data/lib/dato/site/repo/item.rb +0 -80
- data/lib/dato/site/repo/item_type.rb +0 -50
- data/lib/dato/site/repo/menu_item.rb +0 -44
- data/lib/dato/site/repo/role.rb +0 -42
- data/lib/dato/site/repo/search_result.rb +0 -14
- data/lib/dato/site/repo/site.rb +0 -23
- data/lib/dato/site/repo/upload.rb +0 -59
- data/lib/dato/site/repo/upload_request.rb +0 -19
- data/lib/dato/site/repo/user.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7107aad93e6809c4140c2167e1d5ce2cc446c45bf05e66521916a357a52f2b2a
|
4
|
+
data.tar.gz: a3f336225fa11c3d721b07171b432201326b03e58fb394ec0f26911c5320f8e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df93d0a0883dd2a6d728cb5f8ceb7e4b6c46f9063a75bc79ecf1442458f67f5a32aa0a95f7be9a9fc89360b02636206c1bf4bcc6f7689847eb2d2c7e9a269969
|
7
|
+
data.tar.gz: 4a733da2b3626f47018fc6fadefb96d50ffd4959b871f952c78c382225504faa6d894d4aaaed68ba458d91fa6e138fe18ec2e28d550d840a2771c6e823cf48a4
|
data/Rakefile
CHANGED
@@ -1,44 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'bundler/gem_tasks'
|
3
3
|
require 'rspec/core/rake_task'
|
4
|
-
require 'open-uri'
|
5
|
-
|
6
|
-
require_relative './build/build_client'
|
7
4
|
|
8
5
|
RSpec::Core::RakeTask.new(:spec)
|
9
|
-
|
10
6
|
task default: :spec
|
11
|
-
|
12
|
-
desc 'Regenerates the client starting from the JSON Hyperschema'
|
13
|
-
task :regenerate do
|
14
|
-
BuildClient.new(
|
15
|
-
open('https://site-api.datocms.com/docs/site-api-hyperschema.json').read,
|
16
|
-
'site',
|
17
|
-
%w(session item upload user#update)
|
18
|
-
).build
|
19
|
-
|
20
|
-
BuildClient.new(
|
21
|
-
open('https://site-api.datocms.com/docs/account-api-hyperschema.json').read,
|
22
|
-
'account',
|
23
|
-
%w(
|
24
|
-
session
|
25
|
-
account#create account#reset_password
|
26
|
-
subscription
|
27
|
-
portal_session
|
28
|
-
)
|
29
|
-
).build
|
30
|
-
end
|
31
|
-
|
32
|
-
desc 'Open an irb (or pry) session preloaded with this gem'
|
33
|
-
task :console do
|
34
|
-
begin
|
35
|
-
require 'pry'
|
36
|
-
gem_name = File.basename(Dir.pwd)
|
37
|
-
sh %(pry -I lib -r #{gem_name}.rb)
|
38
|
-
rescue LoadError => _
|
39
|
-
sh %(irb -rubygems -I lib -r #{gem_name}.rb)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
require 'rubocop/rake_task'
|
44
|
-
RuboCop::RakeTask.new
|
data/lib/dato/account/client.rb
CHANGED
@@ -1,79 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require '
|
3
|
-
require 'faraday_middleware'
|
4
|
-
require 'json'
|
5
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
-
|
7
|
-
require 'dato/version'
|
8
|
-
|
9
|
-
require 'dato/account/repo/account'
|
10
|
-
require 'dato/account/repo/site'
|
11
|
-
require 'dato/account/repo/deploy_event'
|
12
|
-
require 'dato/api_error'
|
13
|
-
|
14
|
-
require 'cacert'
|
2
|
+
require 'dato/api_client'
|
15
3
|
|
16
4
|
module Dato
|
17
5
|
module Account
|
18
6
|
class Client
|
19
|
-
|
20
|
-
account: Repo::Account,
|
21
|
-
sites: Repo::Site,
|
22
|
-
deploy_events: Repo::DeployEvent
|
23
|
-
}.freeze
|
24
|
-
|
25
|
-
attr_reader :token, :base_url, :schema, :extra_headers
|
26
|
-
|
27
|
-
def initialize(token, options = {})
|
28
|
-
@token = token
|
29
|
-
@base_url = options[:base_url] || 'https://account-api.datocms.com'
|
30
|
-
@extra_headers = options[:extra_headers] || {}
|
31
|
-
end
|
32
|
-
|
33
|
-
REPOS.each do |method_name, repo_klass|
|
34
|
-
define_method method_name do
|
35
|
-
instance_variable_set(
|
36
|
-
"@#{method_name}",
|
37
|
-
instance_variable_get("@#{method_name}") ||
|
38
|
-
repo_klass.new(self)
|
39
|
-
)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def request(*args)
|
44
|
-
connection.send(*args).body.with_indifferent_access
|
45
|
-
rescue Faraday::SSLError => e
|
46
|
-
raise e if ENV['SSL_CERT_FILE'] == Cacert.pem
|
47
|
-
|
48
|
-
Cacert.set_in_env
|
49
|
-
request(*args)
|
50
|
-
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
51
|
-
raise e
|
52
|
-
rescue Faraday::ClientError => e
|
53
|
-
raise ApiError, e
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def connection
|
59
|
-
options = {
|
60
|
-
url: base_url,
|
61
|
-
headers: extra_headers.merge(
|
62
|
-
'Accept' => 'application/json',
|
63
|
-
'Content-Type' => 'application/json',
|
64
|
-
'Authorization' => "Bearer #{@token}",
|
65
|
-
'User-Agent' => "ruby-client v#{Dato::VERSION}"
|
66
|
-
)
|
67
|
-
}
|
7
|
+
include ApiClient
|
68
8
|
|
69
|
-
|
70
|
-
c.request :json
|
71
|
-
c.response :json, content_type: /\bjson$/
|
72
|
-
c.response :raise_error
|
73
|
-
c.use FaradayMiddleware::FollowRedirects
|
74
|
-
c.adapter :net_http
|
75
|
-
end
|
76
|
-
end
|
9
|
+
json_schema 'account-api'
|
77
10
|
end
|
78
11
|
end
|
79
12
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
require 'json_schema'
|
5
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
+
require 'active_support/inflector'
|
7
|
+
|
8
|
+
require 'dato/version'
|
9
|
+
require 'dato/repo'
|
10
|
+
|
11
|
+
require 'dato/api_error'
|
12
|
+
|
13
|
+
require 'cacert'
|
14
|
+
|
15
|
+
module Dato
|
16
|
+
module ApiClient
|
17
|
+
def self.included(base)
|
18
|
+
base.extend ClassMethods
|
19
|
+
|
20
|
+
base.class_eval do
|
21
|
+
attr_reader :token, :base_url, :schema, :extra_headers
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def json_schema(subdomain)
|
27
|
+
define_method(:initialize) do |token, options = {}|
|
28
|
+
@token = token
|
29
|
+
@base_url = options[:base_url] || "https://#{subdomain}.datocms.com"
|
30
|
+
@extra_headers = options[:extra_headers] || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
url = URI.parse("https://#{subdomain}.datocms.com/docs/#{subdomain}-hyperschema.json")
|
34
|
+
response = Net::HTTP.get(url)
|
35
|
+
|
36
|
+
schema = JsonSchema.parse!(JSON.parse(response))
|
37
|
+
schema.expand_references!
|
38
|
+
|
39
|
+
schema.definitions.each do |type, schema|
|
40
|
+
is_collection = schema.links.select{|x| x.rel === "instances"}.any?
|
41
|
+
|
42
|
+
if is_collection
|
43
|
+
type = type.pluralize
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method(type) do
|
47
|
+
instance_variable_set(
|
48
|
+
"@#{type}",
|
49
|
+
instance_variable_get("@#{type}") ||
|
50
|
+
Dato::Repo.new(self, type, schema)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def request(*args)
|
58
|
+
connection.send(*args).body.with_indifferent_access
|
59
|
+
rescue Faraday::SSLError => e
|
60
|
+
raise e if ENV['SSL_CERT_FILE'] == Cacert.pem
|
61
|
+
|
62
|
+
Cacert.set_in_env
|
63
|
+
request(*args)
|
64
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
65
|
+
puts e.message
|
66
|
+
raise e
|
67
|
+
rescue Faraday::ClientError => e
|
68
|
+
error = ApiError.new(e)
|
69
|
+
puts '===='
|
70
|
+
puts error.message
|
71
|
+
puts '===='
|
72
|
+
raise error
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def connection
|
78
|
+
options = {
|
79
|
+
url: base_url,
|
80
|
+
headers: extra_headers.merge(
|
81
|
+
'Accept' => 'application/json',
|
82
|
+
'Content-Type' => 'application/json',
|
83
|
+
'Authorization' => "Bearer #{@token}",
|
84
|
+
'User-Agent' => "ruby-client v#{Dato::VERSION}",
|
85
|
+
'X-Api-Version' => "2"
|
86
|
+
)
|
87
|
+
}
|
88
|
+
|
89
|
+
@connection ||= Faraday.new(options) do |c|
|
90
|
+
c.request :json
|
91
|
+
c.response :json, content_type: /\bjson$/
|
92
|
+
c.response :raise_error
|
93
|
+
c.use FaradayMiddleware::FollowRedirects
|
94
|
+
c.adapter :net_http
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -1,21 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Dato
|
3
3
|
class JsonApiSerializer
|
4
|
-
attr_reader :
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
type:,
|
9
|
-
attributes: [],
|
10
|
-
required_attributes: [],
|
11
|
-
relationships: {},
|
12
|
-
required_relationships: []
|
13
|
-
)
|
4
|
+
attr_reader :link, :type
|
5
|
+
|
6
|
+
def initialize(type, link)
|
7
|
+
@link = link
|
14
8
|
@type = type
|
15
|
-
@attributes = attributes
|
16
|
-
@required_attributes = required_attributes
|
17
|
-
@relationships = relationships
|
18
|
-
@required_relationships = required_relationships
|
19
9
|
end
|
20
10
|
|
21
11
|
def serialize(resource, id = nil)
|
@@ -37,7 +27,7 @@ module Dato
|
|
37
27
|
def serialized_attributes(resource)
|
38
28
|
result = {}
|
39
29
|
|
40
|
-
attributes.each do |attribute|
|
30
|
+
attributes(resource).each do |attribute|
|
41
31
|
if resource.key? attribute
|
42
32
|
result[attribute] = resource[attribute]
|
43
33
|
elsif required_attributes.include? attribute
|
@@ -54,7 +44,6 @@ module Dato
|
|
54
44
|
relationships.each do |relationship, meta|
|
55
45
|
if resource.key? relationship
|
56
46
|
value = resource[relationship]
|
57
|
-
|
58
47
|
data = if value
|
59
48
|
if meta[:collection]
|
60
49
|
value.map do |id|
|
@@ -66,12 +55,78 @@ module Dato
|
|
66
55
|
end
|
67
56
|
result[relationship] = { data: data }
|
68
57
|
|
69
|
-
elsif required_relationships.include?
|
58
|
+
elsif required_relationships.include?(relationship)
|
70
59
|
throw "Required attribute: #{relationship}"
|
71
60
|
end
|
72
61
|
end
|
73
62
|
|
74
63
|
result
|
75
64
|
end
|
65
|
+
|
66
|
+
def attributes(resource)
|
67
|
+
if type == "item"
|
68
|
+
resource.keys - [:item_type, :id]
|
69
|
+
end
|
70
|
+
|
71
|
+
link_attributes["properties"].keys.map(&:to_sym)
|
72
|
+
end
|
73
|
+
|
74
|
+
def required_attributes
|
75
|
+
if type == "item"
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
(link_attributes.required || []).map(&:to_sym)
|
80
|
+
end
|
81
|
+
|
82
|
+
def relationships
|
83
|
+
if type == "item"
|
84
|
+
{
|
85
|
+
item_type: { collection: false, type: 'item_type' }
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
if !link_relationships
|
90
|
+
return {}
|
91
|
+
end
|
92
|
+
|
93
|
+
link_relationships.properties.reduce({}) do |acc, (relationship, schema)|
|
94
|
+
is_collection = schema.properties["data"].type.first == 'array'
|
95
|
+
|
96
|
+
definition = if is_collection
|
97
|
+
schema.properties['data'].items
|
98
|
+
elsif schema.properties['data'].type.first == 'object'
|
99
|
+
schema.properties['data']
|
100
|
+
else
|
101
|
+
schema.properties['data'].any_of.find do |option|
|
102
|
+
option.type.first == 'object'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
type = definition.properties['type']
|
107
|
+
.pattern.source.gsub(/(^\^|\$$)/, '')
|
108
|
+
|
109
|
+
acc[relationship.to_sym] = {
|
110
|
+
collection: is_collection,
|
111
|
+
type: type,
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def required_relationships
|
117
|
+
if type == "item"
|
118
|
+
%i(item_type)
|
119
|
+
end
|
120
|
+
|
121
|
+
(link_relationships.required || []).map(&:to_sym)
|
122
|
+
end
|
123
|
+
|
124
|
+
def link_attributes
|
125
|
+
link.schema.properties["data"].properties["attributes"]
|
126
|
+
end
|
127
|
+
|
128
|
+
def link_relationships
|
129
|
+
link.schema.properties["data"].properties["relationships"]
|
130
|
+
end
|
76
131
|
end
|
77
132
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Dato
|
2
|
+
class Paginator
|
3
|
+
def initialize(client, base_endpoint, filters)
|
4
|
+
@client, @base_endpoint, @filters = client, base_endpoint, filters
|
5
|
+
end
|
6
|
+
|
7
|
+
def response
|
8
|
+
items_per_page = 100
|
9
|
+
|
10
|
+
base_response = @client.request(
|
11
|
+
:get, @base_endpoint, @filters.dup.merge('page[limit]' => items_per_page)
|
12
|
+
)
|
13
|
+
|
14
|
+
extra_pages = (
|
15
|
+
base_response[:meta][:total_count] / items_per_page.to_f
|
16
|
+
).ceil - 1
|
17
|
+
|
18
|
+
extra_pages.times do |page|
|
19
|
+
base_response[:data] += @client.request(
|
20
|
+
:get,
|
21
|
+
@base_endpoint,
|
22
|
+
@filters.dup.merge(
|
23
|
+
'page[offset]' => items_per_page * (page + 1),
|
24
|
+
'page[limit]' => items_per_page
|
25
|
+
)
|
26
|
+
)[:data]
|
27
|
+
end
|
28
|
+
|
29
|
+
base_response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/dato/repo.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'dato/json_api_serializer'
|
3
|
+
require 'dato/json_api_deserializer'
|
4
|
+
require 'dato/paginator'
|
5
|
+
|
6
|
+
module Dato
|
7
|
+
class Repo
|
8
|
+
attr_reader :client, :type, :schema
|
9
|
+
|
10
|
+
IDENTITY_REGEXP = /\{\(.*?definitions%2F(.*?)%2Fdefinitions%2Fidentity\)}/
|
11
|
+
|
12
|
+
METHOD_NAMES = {
|
13
|
+
"instances" => :all,
|
14
|
+
"self" => :find,
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize(client, type, schema)
|
18
|
+
@client = client
|
19
|
+
@type = type
|
20
|
+
@schema = schema
|
21
|
+
|
22
|
+
schema.links.each do |link|
|
23
|
+
method_name = METHOD_NAMES.fetch(link.rel, link.rel)
|
24
|
+
|
25
|
+
self.define_singleton_method(method_name) do |*args|
|
26
|
+
min_arguments_count = [
|
27
|
+
link.href.scan(IDENTITY_REGEXP).size,
|
28
|
+
link.schema && link.method != :get ? 1 : 0
|
29
|
+
].sum
|
30
|
+
|
31
|
+
args.size >= min_arguments_count or
|
32
|
+
raise ArgumentError.new(
|
33
|
+
"wrong number of arguments (given #{args.size}, expected #{min_arguments_count})"
|
34
|
+
)
|
35
|
+
|
36
|
+
last_url_id = nil
|
37
|
+
|
38
|
+
url = link["href"].gsub(IDENTITY_REGEXP) do |_stuff|
|
39
|
+
last_url_id = args.shift.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
response = if %i(post put).include?(link.method)
|
43
|
+
body = if link.schema
|
44
|
+
unserialized_body = args.shift
|
45
|
+
|
46
|
+
JsonApiSerializer.new(type, link).serialize(
|
47
|
+
unserialized_body,
|
48
|
+
last_url_id
|
49
|
+
)
|
50
|
+
else
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
client.request(link.method, url, body)
|
55
|
+
|
56
|
+
elsif link.method == :delete
|
57
|
+
client.request(:delete, url)
|
58
|
+
|
59
|
+
elsif link.method == :get
|
60
|
+
query_string = args.shift
|
61
|
+
|
62
|
+
all_pages = (args[0] || {}).
|
63
|
+
symbolize_keys.
|
64
|
+
fetch(:all_pages, false)
|
65
|
+
|
66
|
+
is_paginated_endpoint = link.schema &&
|
67
|
+
link.schema.properties.has_key?("page[limit]")
|
68
|
+
|
69
|
+
if is_paginated_endpoint && all_pages
|
70
|
+
Paginator.new(client, url, query_string).response
|
71
|
+
else
|
72
|
+
client.request(:get, url, query_string)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
options = if args.any?
|
77
|
+
args.shift.symbolize_keys
|
78
|
+
else
|
79
|
+
{}
|
80
|
+
end
|
81
|
+
|
82
|
+
if options.fetch(:deserialize_response, true)
|
83
|
+
JsonApiDeserializer.new.deserialize(response)
|
84
|
+
else
|
85
|
+
response
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|