flapjack-diner 2.0.0.pre.alpha.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -10
- data/README.md +165 -272
- data/flapjack-diner.gemspec +1 -1
- data/lib/flapjack-diner.rb +54 -25
- data/lib/flapjack-diner/argument_validator.rb +0 -17
- data/lib/flapjack-diner/configuration.rb +417 -0
- data/lib/flapjack-diner/log_formatter.rb +22 -0
- data/lib/flapjack-diner/query.rb +114 -0
- data/lib/flapjack-diner/relationships.rb +180 -0
- data/lib/flapjack-diner/request.rb +280 -0
- data/lib/flapjack-diner/resources.rb +64 -0
- data/lib/flapjack-diner/response.rb +91 -0
- data/lib/flapjack-diner/tools.rb +46 -456
- data/lib/flapjack-diner/utility.rb +16 -0
- data/lib/flapjack-diner/version.rb +1 -1
- data/spec/flapjack-diner_spec.rb +9 -18
- data/spec/{resources/relationships_spec.rb → relationships_spec.rb} +75 -29
- data/spec/resources/checks_spec.rb +7 -7
- data/spec/resources/contacts_spec.rb +21 -19
- data/spec/resources/events_spec.rb +13 -13
- data/spec/resources/maintenance_periods_spec.rb +3 -3
- data/spec/resources/media_spec.rb +3 -3
- data/spec/resources/metrics_spec.rb +1 -1
- data/spec/resources/rules_spec.rb +278 -0
- data/spec/resources/states_spec.rb +1 -1
- data/spec/resources/statistics_spec.rb +1 -1
- data/spec/resources/tags_spec.rb +75 -19
- data/spec/support/fixture_data.rb +57 -98
- metadata +21 -29
- data/.rubocop.yml +0 -21
- data/.rubocop_todo.yml +0 -135
- data/lib/flapjack-diner/resources/acceptors.rb +0 -77
- data/lib/flapjack-diner/resources/checks.rb +0 -52
- data/lib/flapjack-diner/resources/contacts.rb +0 -54
- data/lib/flapjack-diner/resources/events.rb +0 -54
- data/lib/flapjack-diner/resources/maintenance_periods.rb +0 -76
- data/lib/flapjack-diner/resources/media.rb +0 -75
- data/lib/flapjack-diner/resources/metrics.rb +0 -23
- data/lib/flapjack-diner/resources/rejectors.rb +0 -77
- data/lib/flapjack-diner/resources/relationships.rb +0 -314
- data/lib/flapjack-diner/resources/states.rb +0 -24
- data/lib/flapjack-diner/resources/statistics.rb +0 -24
- data/lib/flapjack-diner/resources/tags.rb +0 -47
- data/spec/resources/acceptors_spec.rb +0 -278
- data/spec/resources/rejectors_spec.rb +0 -278
@@ -0,0 +1,22 @@
|
|
1
|
+
module Flapjack
|
2
|
+
module Diner
|
3
|
+
class LogFormatter #:nodoc:
|
4
|
+
TAG_NAME = Flapjack::Diner.name
|
5
|
+
|
6
|
+
attr_accessor :level, :logger, :current_time
|
7
|
+
|
8
|
+
def initialize(logger, level)
|
9
|
+
@logger = logger
|
10
|
+
@level = level.to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
def format(request, response)
|
14
|
+
current_time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z")
|
15
|
+
http_method = request.http_method.name.split("::").last.upcase
|
16
|
+
path = request.path.to_s
|
17
|
+
content_length = response.respond_to?(:headers) ? response.headers['Content-Length'] : response['Content-Length']
|
18
|
+
@logger.send @level, "[#{TAG_NAME}] [#{current_time}] #{response.code} \"#{http_method} #{path}\" #{content_length || '-'} "
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'flapjack-diner/utility'
|
2
|
+
|
3
|
+
module Flapjack
|
4
|
+
module Diner
|
5
|
+
module Query
|
6
|
+
|
7
|
+
def self.validate_params(query = {}, &validation)
|
8
|
+
return unless block_given?
|
9
|
+
query = {} if [].eql?(query)
|
10
|
+
case query
|
11
|
+
when Array
|
12
|
+
query.each do |q|
|
13
|
+
ArgumentValidator.new(q).instance_eval(&validation)
|
14
|
+
end
|
15
|
+
else
|
16
|
+
ArgumentValidator.new(query).instance_eval(&validation)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# copied from Rack::Utils -- builds the query string for GETs
|
21
|
+
def self.build_nested(value, prefix = nil)
|
22
|
+
case value
|
23
|
+
when Array
|
24
|
+
build_array(value, prefix)
|
25
|
+
when Hash
|
26
|
+
build_hash(value, prefix)
|
27
|
+
else
|
28
|
+
build_data(value, prefix)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# used for the JSON data hashes in POST, PUT, DELETE
|
33
|
+
def self.prepare_nested(value)
|
34
|
+
case value
|
35
|
+
when Array
|
36
|
+
prepare_array(value)
|
37
|
+
when Hash
|
38
|
+
prepare_hash(value)
|
39
|
+
else
|
40
|
+
prepare_data(value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.unwrap_uuids(*args)
|
45
|
+
ids = args.select {|a| a.is_a?(String) }
|
46
|
+
raise "IDs must be RFC 4122-compliant UUIDs" unless ids.all? {|id|
|
47
|
+
id =~ /^#{Flapjack::Diner::UUID_RE}$/i
|
48
|
+
}
|
49
|
+
ids
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.unwrap_data(*args)
|
53
|
+
data = args.reject {|a| a.is_a?(String) || a.is_a?(Integer) }
|
54
|
+
unless data.all? {|a| a.is_a?(Hash) }
|
55
|
+
raise 'Data must be passed as a Hash, or multiple Hashes'
|
56
|
+
end
|
57
|
+
return Flapjack::Diner::Utility.symbolize(data.first) if data.size == 1
|
58
|
+
data.each_with_object([]) {|d, o| o << Flapjack::Diner::Utility.symbolize(d) }
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def self.build_array(value, prefix)
|
64
|
+
value.map {|v| build_nested(v, "#{prefix}[]") }.join('&')
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.build_hash(value, prefix)
|
68
|
+
value.map do |k, v|
|
69
|
+
data = prefix ? "#{prefix}[#{k}]" : k
|
70
|
+
build_nested(v, data)
|
71
|
+
end.join('&')
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.build_data(value, prefix)
|
75
|
+
if value.respond_to?(:iso8601)
|
76
|
+
raise(ArgumentError, 'Value must be a Hash') if prefix.nil?
|
77
|
+
"#{escape(prefix)}=#{escape(value.iso8601)}"
|
78
|
+
elsif value.is_a?(String) || value.is_a?(Integer)
|
79
|
+
raise(ArgumentError, 'Value must be a Hash') if prefix.nil?
|
80
|
+
"#{escape(prefix)}=#{escape(value.to_s)}"
|
81
|
+
else
|
82
|
+
prefix
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.escape(s)
|
87
|
+
URI.encode_www_form_component(s)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.prepare_array(value)
|
91
|
+
value.map {|v| prepare_nested(v) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.prepare_hash(value)
|
95
|
+
value.each_with_object({}) do |(k, v), a|
|
96
|
+
a[k] = prepare_nested(v)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.prepare_data(value)
|
101
|
+
if value.respond_to?(:iso8601)
|
102
|
+
value.iso8601
|
103
|
+
else
|
104
|
+
case value
|
105
|
+
when Integer, TrueClass, FalseClass, NilClass
|
106
|
+
value
|
107
|
+
else
|
108
|
+
value.to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'flapjack-diner/query'
|
2
|
+
|
3
|
+
module Flapjack
|
4
|
+
module Diner
|
5
|
+
module Relationships
|
6
|
+
|
7
|
+
# FIXME include option for GET should check config settings for includable
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
# base.extend ClassMethods
|
11
|
+
base.class_eval do
|
12
|
+
|
13
|
+
::Flapjack::Diner::Configuration::RESOURCES.each_pair do |resource, config|
|
14
|
+
mappings = config[:relationships]
|
15
|
+
next if mappings.nil?
|
16
|
+
|
17
|
+
res = config[:resource]
|
18
|
+
resource_id_validator = :uuid
|
19
|
+
|
20
|
+
# # NB: no non-GET singular link methods, so commented out for now
|
21
|
+
# mappings.select {|n, a| a[:post] && a[:link] && :singular.eql?(a[:number]) }.each do |linked, assoc|
|
22
|
+
# linked_id_validator = :singular_link_uuid
|
23
|
+
|
24
|
+
# define_singleton_method("create_#{res}_link_#{linked}") do |resource_id, linked_id|
|
25
|
+
# validations_proc = proc do
|
26
|
+
# Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_id => linked_id) do
|
27
|
+
# validate :query => :resource_id, :as => resource_id_validator
|
28
|
+
# validate :query => :linked_id, :as => linked_id_validator
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
|
32
|
+
# resp = Flapjack::Diner::Request.new(
|
33
|
+
# linked, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
34
|
+
# :ids => linked_id, :validations_proc => validations_proc
|
35
|
+
# ).post_links
|
36
|
+
# @response = Flapjack::Diner::Response.new(resp)
|
37
|
+
# @response.process
|
38
|
+
# @response.output
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
|
42
|
+
mappings.select {|n, a| a[:post] && a[:link] && :multiple.eql?(a[:number]) }.each do |linked, assoc|
|
43
|
+
type = ::Flapjack::Diner::Configuration::RESOURCES[linked][:resource]
|
44
|
+
linked_ids_validator = :multiple_link_uuid
|
45
|
+
|
46
|
+
define_singleton_method("create_#{res}_link_#{linked}") do |resource_id, *linked_ids|
|
47
|
+
validations_proc = proc do
|
48
|
+
Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_ids => linked_ids) do
|
49
|
+
validate :query => :resource_id, :as => resource_id_validator
|
50
|
+
validate :query => :linked_ids, :as => linked_ids_validator
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
resp = Flapjack::Diner::Request.new(
|
55
|
+
type, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
56
|
+
:ids => linked_ids, :validations_proc => validations_proc
|
57
|
+
).post_links
|
58
|
+
@response = Flapjack::Diner::Response.new(resp)
|
59
|
+
@response.process
|
60
|
+
@response.output
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
mappings.select {|n, a| a[:get] && a[:link] }.each do |linked, assoc|
|
65
|
+
define_singleton_method("#{res}_link_#{linked}") do |resource_id, opts = {}|
|
66
|
+
validations_proc = proc do |data|
|
67
|
+
Flapjack::Diner::Query.validate_params(:resource_id => resource_id) do
|
68
|
+
validate :query => :resource_id, :as => resource_id_validator
|
69
|
+
end
|
70
|
+
|
71
|
+
Flapjack::Diner::Query.validate_params(opts) do
|
72
|
+
validate :query => [:fields, :sort, :include], :as => :string_or_array_of_strings
|
73
|
+
validate :query => :filter, :as => :hash
|
74
|
+
validate :query => [:page, :per_page], :as => :positive_integer
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
resp = Flapjack::Diner::Request.new(
|
79
|
+
linked, "/#{resource}/#{resource_id}/#{linked}", :data => [opts],
|
80
|
+
:assoc => linked, :validations_proc => validations_proc
|
81
|
+
).get
|
82
|
+
@response = Flapjack::Diner::Response.new(resp)
|
83
|
+
@response.process
|
84
|
+
@response.output
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# # NB: no non-GET singular link methods, so commented out for now
|
89
|
+
# mappings.select {|n, a| a[:patch] && a[:link] && :singular.eql?(a[:number]) }.each do |linked, assoc|
|
90
|
+
# linked_id_validator = :singular_link_uuid
|
91
|
+
|
92
|
+
# define_singleton_method("update_#{res}_link_#{linked}") do |resource_id, linked_id|
|
93
|
+
# validations_proc = proc do
|
94
|
+
# Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_id => linked_id) do
|
95
|
+
# validate :query => :resource_id, :as => resource_id_validator
|
96
|
+
# validate :query => :linked_id, :as => linked_id_validator
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
|
100
|
+
# resp = Flapjack::Diner::Request.new(
|
101
|
+
# linked, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
102
|
+
# :ids => linked_id, :validations_proc => validation_proc, :single => true
|
103
|
+
# ).patch_links
|
104
|
+
# @response = Flapjack::Diner::Response.new(resp)
|
105
|
+
# @response.process
|
106
|
+
# @response.output
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
|
110
|
+
mappings.select {|n, a| a[:patch] && a[:link] && :multiple.eql?(a[:number]) }.each do |linked, assoc|
|
111
|
+
type = ::Flapjack::Diner::Configuration::RESOURCES[linked][:resource]
|
112
|
+
linked_ids_validator = :multiple_link_uuid
|
113
|
+
|
114
|
+
define_singleton_method("update_#{res}_link_#{linked}") do |resource_id, *linked_ids|
|
115
|
+
validations_proc = proc do
|
116
|
+
Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_ids => linked_ids) do
|
117
|
+
validate :query => :resource_id, :as => resource_id_validator
|
118
|
+
validate :query => :linked_id, :as => linked_ids_validator
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
resp = Flapjack::Diner::Request.new(
|
123
|
+
type, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
124
|
+
:ids => linked_ids, :validations_proc => validations_proc
|
125
|
+
).patch_links
|
126
|
+
@response = Flapjack::Diner::Response.new(resp)
|
127
|
+
@response.process
|
128
|
+
@response.output
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# # NB: no non-GET singular link methods, so commented out for now
|
133
|
+
# mappings.select {|n, a| a[:delete] && a[:link] && :singular.eql?(a[:number]) }.each do |linked, assoc|
|
134
|
+
# linked_id_validator = :singular_link_uuid
|
135
|
+
|
136
|
+
# define_singleton_method("delete_#{res}_link_#{linked}") do |resource_id, linked_id|
|
137
|
+
# validations_proc = proc do
|
138
|
+
# Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_id => linked_id) do
|
139
|
+
# validate :query => :resource_id, :as => resource_id_validator
|
140
|
+
# validate :query => :linked_id, :as => linked_id_validator
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
|
144
|
+
# resp = Flapjack::Diner::Request.new(
|
145
|
+
# linked, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
146
|
+
# :ids => linked_ids :validations_proc => validations_proc
|
147
|
+
# ).delete_links
|
148
|
+
# @response = Flapjack::Diner::Response.new(resp)
|
149
|
+
# @response.process
|
150
|
+
# @response.output
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
|
154
|
+
mappings.select {|n, a| a[:delete] && a[:link] && :multiple.eql?(a[:number]) }.each do |linked, assoc|
|
155
|
+
type = ::Flapjack::Diner::Configuration::RESOURCES[linked][:resource]
|
156
|
+
linked_ids_validator = :uuid_or_array_of_uuids
|
157
|
+
|
158
|
+
define_singleton_method("delete_#{res}_link_#{linked}") do |resource_id, *linked_ids|
|
159
|
+
validations_proc = proc do
|
160
|
+
Flapjack::Diner::Query.validate_params(:resource_id => resource_id, :linked_ids => linked_ids) do
|
161
|
+
validate :query => :resource_id, :as => resource_id_validator
|
162
|
+
validate :query => :linked_ids, :as => linked_ids_validator
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
resp = Flapjack::Diner::Request.new(
|
167
|
+
type, "/#{resource}/#{resource_id}/relationships/#{linked}",
|
168
|
+
:ids => linked_ids, :validations_proc => validations_proc
|
169
|
+
).delete_links
|
170
|
+
@response = Flapjack::Diner::Response.new(resp)
|
171
|
+
@response.process
|
172
|
+
@response.output
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
require 'flapjack-diner/query'
|
5
|
+
|
6
|
+
module Flapjack
|
7
|
+
module Diner
|
8
|
+
class Request
|
9
|
+
|
10
|
+
def initialize(type, path, opts = {})
|
11
|
+
@type = type
|
12
|
+
@path = path
|
13
|
+
@ids = opts.key?(:ids) ? opts[:ids] :
|
14
|
+
(opts[:data].nil? ? nil : Flapjack::Diner::Query.unwrap_uuids(*opts[:data]))
|
15
|
+
@data = opts[:data].nil? ? nil : Flapjack::Diner::Query.unwrap_data(*opts[:data])
|
16
|
+
@assoc = opts[:assoc]
|
17
|
+
|
18
|
+
unless @data.nil?
|
19
|
+
validations = opts[:validations]
|
20
|
+
unless validations.nil?
|
21
|
+
Flapjack::Diner::Query.validate_params(@data) do
|
22
|
+
validations.each_pair { |k,v| validate :query => k, :as => v }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
validations_proc = opts[:validations_proc]
|
28
|
+
validations_proc.call unless validations_proc.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def post
|
32
|
+
req_data = nil
|
33
|
+
jsonapi_ext = ""
|
34
|
+
|
35
|
+
case @data
|
36
|
+
when Array
|
37
|
+
req_data = @data.collect {|d| record_data(d, :post) }
|
38
|
+
jsonapi_ext = "; ext=bulk"
|
39
|
+
when Hash
|
40
|
+
req_data = record_data(@data, :post)
|
41
|
+
end
|
42
|
+
req_uri = build_uri
|
43
|
+
|
44
|
+
# TODO send current character encoding in content-type ?
|
45
|
+
Flapjack::Diner.post(req_uri.request_uri,
|
46
|
+
:body => Flapjack::Diner::Query.prepare_nested(:data => req_data).to_json,
|
47
|
+
:headers => {'Content-Type' => "application/vnd.api+json#{jsonapi_ext}"})
|
48
|
+
end
|
49
|
+
|
50
|
+
def post_links
|
51
|
+
@data = @ids.collect {|id| {:type => @type, :id => id}}
|
52
|
+
@ids = nil
|
53
|
+
req_uri = build_uri
|
54
|
+
Flapjack::Diner.post(req_uri.request_uri,
|
55
|
+
:body => Flapjack::Diner::Query.prepare_nested(:data => @data).to_json,
|
56
|
+
:headers => {'Content-Type' => 'application/vnd.api+json'})
|
57
|
+
end
|
58
|
+
|
59
|
+
def get
|
60
|
+
@data = @data.reduce({}, &:merge) if @data.is_a?(Array)
|
61
|
+
if !@ids.nil? && (@ids.size > 1)
|
62
|
+
if @data[:filter].nil?
|
63
|
+
@data[:filter] = {:id => @ids}
|
64
|
+
elsif !data[:filter].key?(:id)
|
65
|
+
@data[:filter][:id] = @ids
|
66
|
+
else
|
67
|
+
@data[:filter][:id] |= @ids
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
filt = @data.delete(:filter)
|
72
|
+
unless filt.nil?
|
73
|
+
@data[:filter] = filt.each_with_object([]) do |(k, v), memo|
|
74
|
+
value = case v
|
75
|
+
when Array, Set
|
76
|
+
v.to_a.join("|")
|
77
|
+
else
|
78
|
+
v.to_s
|
79
|
+
end
|
80
|
+
memo << (@assoc.nil? ? "#{k}:#{value}" : "#{@assoc}.#{k}:#{value}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
incl = @data[:include]
|
85
|
+
unless incl.nil?
|
86
|
+
case incl
|
87
|
+
when Array
|
88
|
+
raise ArgumentError.new("Include parameters must not contain commas") if incl.any? {|i| i =~ /,/}
|
89
|
+
@data[:include] = if @assoc.nil?
|
90
|
+
incl.join(",")
|
91
|
+
else
|
92
|
+
incl.map {|i|
|
93
|
+
if i.eql?(@assoc.to_s) || (i =~ /^#{@assoc}\./)
|
94
|
+
i
|
95
|
+
else
|
96
|
+
"#{@assoc}.#{i}"
|
97
|
+
end
|
98
|
+
}.join(",")
|
99
|
+
end
|
100
|
+
when String
|
101
|
+
raise ArgumentError.new("Include parameters must not contain commas") if incl =~ /,/
|
102
|
+
unless @assoc.nil? || (incl.eql?(@assoc.to_s)) || (incl =~ /^#{@assoc}\./)
|
103
|
+
@data[:include] = "#{@assoc}.#{incl}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
req_uri = build_uri(@data)
|
109
|
+
Flapjack::Diner.get(req_uri.request_uri)
|
110
|
+
end
|
111
|
+
|
112
|
+
def patch
|
113
|
+
req_uri = nil
|
114
|
+
req_data = nil
|
115
|
+
|
116
|
+
jsonapi_ext = ""
|
117
|
+
case @data
|
118
|
+
when Hash
|
119
|
+
raise "Update data does not contain :id" unless @data[:id]
|
120
|
+
req_data = record_data(@data, :patch)
|
121
|
+
@ids = [@data[:id]]
|
122
|
+
req_uri = build_uri
|
123
|
+
when Array
|
124
|
+
ids = []
|
125
|
+
req_data = []
|
126
|
+
@data.each do |d|
|
127
|
+
d_id = d.key?(:id) ? d[:id] : nil
|
128
|
+
@ids << d_id unless d_id.nil? || d_id.empty?
|
129
|
+
req_data << record_data(d, :patch)
|
130
|
+
end
|
131
|
+
raise "Update data must each contain :id" unless @ids.size == @data.size
|
132
|
+
req_uri = build_uri
|
133
|
+
jsonapi_ext = "; ext=bulk"
|
134
|
+
end
|
135
|
+
|
136
|
+
opts = if req_data.nil?
|
137
|
+
{}
|
138
|
+
else
|
139
|
+
{:body => Flapjack::Diner::Query.prepare_nested(:data => req_data).to_json,
|
140
|
+
:headers => {'Content-Type' => "application/vnd.api+json#{jsonapi_ext}"}}
|
141
|
+
end
|
142
|
+
Flapjack::Diner.patch(req_uri.request_uri, opts)
|
143
|
+
end
|
144
|
+
|
145
|
+
def patch_links
|
146
|
+
# data = if opts[:single]
|
147
|
+
# raise "Must provide one ID for a singular link" unless @ids.size == 1
|
148
|
+
# [nil].eql?(@ids) ? nil : {:type => @type, :id => @ids.first}
|
149
|
+
# else
|
150
|
+
data = [[]].eql?(@ids) ? [] : @ids.collect {|id| {:type => @type, :id => id}}
|
151
|
+
# end
|
152
|
+
@ids = nil
|
153
|
+
|
154
|
+
req_uri = build_uri
|
155
|
+
|
156
|
+
opts = {:body => Flapjack::Diner::Query.prepare_nested(:data => data).to_json,
|
157
|
+
:headers => {'Content-Type' => 'application/vnd.api+json'}}
|
158
|
+
Flapjack::Diner.patch(req_uri.request_uri, opts)
|
159
|
+
end
|
160
|
+
|
161
|
+
def delete
|
162
|
+
type = Flapjack::Diner::Configuration::RESOURCES[@type][:resource]
|
163
|
+
|
164
|
+
req_uri = build_uri
|
165
|
+
opts = if @ids.size == 1
|
166
|
+
{}
|
167
|
+
else
|
168
|
+
data = @ids.collect {|id| {:type => type, :id => id} }
|
169
|
+
{:body => Flapjack::Diner::Query.prepare_nested(:data => data).to_json,
|
170
|
+
:headers => {'Content-Type' => 'application/vnd.api+json; ext=bulk'}}
|
171
|
+
end
|
172
|
+
Flapjack::Diner.delete(req_uri.request_uri, opts)
|
173
|
+
end
|
174
|
+
|
175
|
+
def delete_links
|
176
|
+
data = @ids.collect {|id| {:type => @type, :id => id}}
|
177
|
+
@ids = nil
|
178
|
+
req_uri = build_uri
|
179
|
+
opts = {:body => Flapjack::Diner::Query.prepare_nested(:data => data).to_json,
|
180
|
+
:headers => {'Content-Type' => 'application/vnd.api+json'}}
|
181
|
+
Flapjack::Diner.delete(req_uri.request_uri, opts)
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def record_data(source, method)
|
187
|
+
res = Flapjack::Diner::Configuration::RESOURCES[@type]
|
188
|
+
r_type = res[:resource]
|
189
|
+
|
190
|
+
req_data = {}
|
191
|
+
['id', :id].each do |i|
|
192
|
+
req_data[:id] = source[i] if source.key?(i)
|
193
|
+
end
|
194
|
+
req_data[:type] = r_type
|
195
|
+
|
196
|
+
assocs = res[:relationships] || {}
|
197
|
+
|
198
|
+
rel_singular = assocs.inject([]) do |memo, (assoc_name, assoc)|
|
199
|
+
if assoc[method].is_a?(TrueClass) && :singular.eql?(assoc[:number])
|
200
|
+
memo << assoc_name
|
201
|
+
end
|
202
|
+
memo
|
203
|
+
end
|
204
|
+
|
205
|
+
rel_multiple = assocs.inject([]) do |memo, (assoc_name, assoc)|
|
206
|
+
if assoc[method].is_a?(TrueClass) && :multiple.eql?(assoc[:number])
|
207
|
+
memo << assoc_name
|
208
|
+
end
|
209
|
+
memo
|
210
|
+
end
|
211
|
+
|
212
|
+
excluded = [:id, :type] + rel_singular + rel_multiple
|
213
|
+
attrs = source.reject do |k, _|
|
214
|
+
excluded.include?(k.to_sym)
|
215
|
+
end
|
216
|
+
|
217
|
+
req_data[:attributes] = attrs unless attrs.empty?
|
218
|
+
|
219
|
+
rel_data = {}
|
220
|
+
|
221
|
+
rel_singular.each do |singular_link|
|
222
|
+
converted = false
|
223
|
+
[singular_link, singular_link.to_s].each do |sl|
|
224
|
+
next if converted || !source.key?(sl)
|
225
|
+
rel_data[singular_link] = {
|
226
|
+
:data => {
|
227
|
+
:type => singular_link.to_s,
|
228
|
+
:id => source[sl]
|
229
|
+
}
|
230
|
+
}
|
231
|
+
converted = true
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
rel_multiple.each do |multiple_link|
|
236
|
+
converted = false
|
237
|
+
ml_type = Flapjack::Diner::Configuration::RESOURCES[multiple_link][:resource]
|
238
|
+
[multiple_link, multiple_link.to_s].each do |ml|
|
239
|
+
next if converted || !source.key?(ml)
|
240
|
+
rel_data[multiple_link] = {
|
241
|
+
:data => source[ml].map {|id| {:type => ml_type, :id => id} }
|
242
|
+
}
|
243
|
+
converted = true
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
req_data[:relationships] = rel_data unless rel_data.empty?
|
248
|
+
|
249
|
+
req_data
|
250
|
+
end
|
251
|
+
|
252
|
+
def normalise_port(port_str, protocol)
|
253
|
+
if port_str.nil? || port_str.to_i < 1 || port_str.to_i > 65_535
|
254
|
+
'https'.eql?(protocol) ? 443 : 80
|
255
|
+
else
|
256
|
+
port_str.to_i
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def protocol_host_port
|
261
|
+
%r{^(?:(?<protocol>https?)://)
|
262
|
+
(?<host>[a-zA-Z0-9][a-zA-Z0-9\.\-]*[a-zA-Z0-9])
|
263
|
+
(?::(?<port>\d+))?
|
264
|
+
}ix =~ Flapjack::Diner.base_uri
|
265
|
+
|
266
|
+
protocol = protocol.nil? ? 'http' : protocol.downcase
|
267
|
+
[protocol, host, normalise_port(port, protocol)]
|
268
|
+
end
|
269
|
+
|
270
|
+
def build_uri(params = [])
|
271
|
+
pr, ho, po = protocol_host_port
|
272
|
+
@path += "/#{URI.escape(@ids.first.to_s)}" if !@ids.nil? && @ids.size == 1
|
273
|
+
params = params.reduce({}, &:merge) if params.is_a?(Array)
|
274
|
+
query = params.empty? ? nil : Flapjack::Diner::Query.build_nested(params)
|
275
|
+
URI::HTTP.build(:protocol => pr, :host => ho, :port => po,
|
276
|
+
:path => @path, :query => query)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|