pisoni 1.23.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/CHANGELOG.md +9 -0
- data/Gemfile +16 -0
- data/LICENSE +202 -0
- data/Makefile +73 -0
- data/NOTICE +15 -0
- data/README.md +47 -0
- data/Rakefile +27 -0
- data/lib/3scale/core/alert_limit.rb +32 -0
- data/lib/3scale/core/api_client/attributes.rb +56 -0
- data/lib/3scale/core/api_client/collection.rb +19 -0
- data/lib/3scale/core/api_client/operations.rb +233 -0
- data/lib/3scale/core/api_client/resource.rb +52 -0
- data/lib/3scale/core/api_client/support.rb +55 -0
- data/lib/3scale/core/api_client.rb +5 -0
- data/lib/3scale/core/application.rb +67 -0
- data/lib/3scale/core/application_key.rb +34 -0
- data/lib/3scale/core/application_referrer_filter.rb +33 -0
- data/lib/3scale/core/errors.rb +130 -0
- data/lib/3scale/core/event.rb +26 -0
- data/lib/3scale/core/logger.rb +12 -0
- data/lib/3scale/core/metric.rb +32 -0
- data/lib/3scale/core/service.rb +82 -0
- data/lib/3scale/core/service_error.rb +34 -0
- data/lib/3scale/core/service_token.rb +39 -0
- data/lib/3scale/core/transaction.rb +26 -0
- data/lib/3scale/core/usage_limit.rb +40 -0
- data/lib/3scale/core/user.rb +47 -0
- data/lib/3scale/core/utilization.rb +28 -0
- data/lib/3scale/core/version.rb +5 -0
- data/lib/3scale/core.rb +63 -0
- data/lib/3scale_core.rb +1 -0
- data/lib/pisoni.rb +5 -0
- data/pisoni.gemspec +43 -0
- data/spec/alert_limit_spec.rb +72 -0
- data/spec/application_key_spec.rb +97 -0
- data/spec/application_referrer_filter_spec.rb +57 -0
- data/spec/application_spec.rb +188 -0
- data/spec/event_spec.rb +82 -0
- data/spec/metric_spec.rb +115 -0
- data/spec/private_endpoints/event.rb +9 -0
- data/spec/private_endpoints/service_error.rb +10 -0
- data/spec/private_endpoints/transaction.rb +16 -0
- data/spec/service_error_spec.rb +128 -0
- data/spec/service_spec.rb +159 -0
- data/spec/service_token_spec.rb +121 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/transaction_spec.rb +71 -0
- data/spec/usagelimit_spec.rb +52 -0
- data/spec/user_spec.rb +164 -0
- data/spec/utilization_spec.rb +113 -0
- metadata +182 -0
@@ -0,0 +1,233 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
module APIClient
|
4
|
+
module Operations
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.prepend Initializer
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attr_accessor :persisted
|
13
|
+
|
14
|
+
def api_save(api_options = {})
|
15
|
+
if persisted
|
16
|
+
ret = self.class.api_do_put attributes, api_options
|
17
|
+
else
|
18
|
+
ret = self.class.api_do_post attributes, api_options
|
19
|
+
self.persisted = ret[:ok]
|
20
|
+
end
|
21
|
+
if ret[:ok]
|
22
|
+
update_attributes(ret[:attributes])
|
23
|
+
self.dirty = false
|
24
|
+
true
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def api_delete(api_options = {})
|
31
|
+
ok = self.class.api_delete attributes, api_options
|
32
|
+
self.persisted = false if ok
|
33
|
+
ok
|
34
|
+
end
|
35
|
+
|
36
|
+
module Initializer
|
37
|
+
def initialize(*args)
|
38
|
+
self.persisted = false
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
include ThreeScale::Core::Logger
|
45
|
+
|
46
|
+
# CRUD methods
|
47
|
+
|
48
|
+
def api_create(attributes, api_options = {}, &blk)
|
49
|
+
api_create_object :api_do_post, attributes, api_options, &blk
|
50
|
+
end
|
51
|
+
alias_method :api_save, :api_create
|
52
|
+
|
53
|
+
def api_read(attributes, api_options = {}, &blk)
|
54
|
+
api_create_object :api_do_get, attributes, api_options, &blk
|
55
|
+
end
|
56
|
+
alias_method :api_load, :api_read
|
57
|
+
|
58
|
+
def api_update(attributes, api_options = {}, &blk)
|
59
|
+
api_create_object :api_do_put, attributes, api_options, &blk
|
60
|
+
end
|
61
|
+
|
62
|
+
def api_delete(attributes, api_options = {}, &blk)
|
63
|
+
api_do_delete(attributes, api_options, &blk)[:ok]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Helpers
|
67
|
+
|
68
|
+
def api_do_get(attributes, api_options = {}, &blk)
|
69
|
+
blk = filter_404 if blk.nil?
|
70
|
+
api :get, attributes, api_options, &blk
|
71
|
+
end
|
72
|
+
|
73
|
+
def api_do_put(attributes, api_options = {}, &blk)
|
74
|
+
api :put, attributes, api_options, &blk
|
75
|
+
end
|
76
|
+
|
77
|
+
def api_do_post(attributes, api_options = {}, &blk)
|
78
|
+
api :post, attributes, api_options, &blk
|
79
|
+
end
|
80
|
+
|
81
|
+
def api_do_delete(attributes, api_options = {}, &blk)
|
82
|
+
blk = filter_404 if blk.nil?
|
83
|
+
api :delete, attributes, api_options, &blk
|
84
|
+
end
|
85
|
+
|
86
|
+
def api_create_object(method, attributes, api_options = {}, &blk)
|
87
|
+
ret = send method, attributes, api_options.merge(build: true), &blk
|
88
|
+
ret[:object].send :persisted=, true if ret[:object]
|
89
|
+
ret[:object]
|
90
|
+
end
|
91
|
+
|
92
|
+
def filter_404
|
93
|
+
@filter_404_proc ||= proc do |result|
|
94
|
+
result[:response].status != 404
|
95
|
+
end
|
96
|
+
end
|
97
|
+
private :filter_404
|
98
|
+
|
99
|
+
def api_http(method, uri, attributes)
|
100
|
+
# GET, DELETE and HEAD are treated differently by Faraday. We need
|
101
|
+
# to set the body in there.
|
102
|
+
if method == :get or method == :delete
|
103
|
+
Core.faraday.send method, uri do |req|
|
104
|
+
req.body = attributes.to_json
|
105
|
+
end
|
106
|
+
else
|
107
|
+
Core.faraday.send method, uri, attributes.to_json
|
108
|
+
end
|
109
|
+
rescue Faraday::Error::ClientError, SystemCallError => e
|
110
|
+
raise ConnectionError, e
|
111
|
+
end
|
112
|
+
private :api_http
|
113
|
+
|
114
|
+
def api_parse_json(response)
|
115
|
+
raise JSONError, "unacceptable content-type #{response.headers['content-type']} (#{response.headers['server']}): #{response.body[0,512]}" unless response.headers['content-type'].include? 'json'
|
116
|
+
parse_json(response.body)
|
117
|
+
rescue JSON::ParserError => e
|
118
|
+
# you can obtain the error message with
|
119
|
+
# rescue JSONError => e
|
120
|
+
# puts(e.cause ? e.cause.message : e.message)
|
121
|
+
#
|
122
|
+
# e.message will always return a trimmed (bounded) message, while
|
123
|
+
# e.cause.message, when a cause is present, may return a long
|
124
|
+
# message including the whole response body.
|
125
|
+
raise JSONError, e
|
126
|
+
end
|
127
|
+
private :api_parse_json
|
128
|
+
|
129
|
+
# Our current HTTP client (Faraday wrapper) does not expose HTTP
|
130
|
+
# version, which would be convenient for determining whether we have
|
131
|
+
# a keep-alive connection. For that we would probably need to write a
|
132
|
+
# Faraday middleware.
|
133
|
+
#
|
134
|
+
# Anyway, in HTTP/1.0 we are not guaranteed to have a Connection:
|
135
|
+
# response field, so it does not always use Connection: close (they
|
136
|
+
# are closed by default). HTTP/1.1 OTOH does keep-alive by default, so
|
137
|
+
# it will close the connection when actually sending a Connection:
|
138
|
+
# close. So:
|
139
|
+
# HTTP/1.1: KA if no Connection field or if present and not 'close'
|
140
|
+
# HTTP/1.0: no KA unless Connection: keep-alive.
|
141
|
+
# XXX UNDEFINED: no Connection header, depends on HTTP version:
|
142
|
+
# 1.1: keep-alive
|
143
|
+
# 1.0: close
|
144
|
+
def keep_alive_response?(response)
|
145
|
+
response.headers['connection'] != 'close'
|
146
|
+
end
|
147
|
+
private :keep_alive_response?
|
148
|
+
|
149
|
+
def api_response_inspect(method, uri, response, attributes, after, before)
|
150
|
+
"<#{keep_alive_response?(response) ? '=' : '/'}= #{response.status} #{method.upcase} #{uri} [#{attributes}] (#{after - before})"
|
151
|
+
end
|
152
|
+
private :api_response_inspect
|
153
|
+
|
154
|
+
# api method - talk with the remote HTTP service
|
155
|
+
#
|
156
|
+
# method - HTTP method to use
|
157
|
+
# attributes - HTTP request body parameters
|
158
|
+
# options:
|
159
|
+
# :prefix => string/symbol - an attribute prefix, '' for none, else default_prefix
|
160
|
+
# :rprefix => string/symbol - same as above, but for parsing responses
|
161
|
+
# :uri => string - sets the uri for this particular request
|
162
|
+
# :raise => boolean - raise APIError on error, defaults to true
|
163
|
+
# :build => boolean - create a new object with response's JSON if response is ok, defaults to false
|
164
|
+
# block (optional) - receives two params: http status code and attributes
|
165
|
+
# this block if present handles error responses, invalidates :raise option,
|
166
|
+
# you should return an array of [raise (boolean), built_object (if any) or nil]
|
167
|
+
#
|
168
|
+
# returns:
|
169
|
+
# a hash consisting of:
|
170
|
+
# :response - http response
|
171
|
+
# :response_json - http response parsed JSON
|
172
|
+
# :ok - whether the response code was ok when related to the http method
|
173
|
+
# :object - nil or the object created if applicable
|
174
|
+
# :attributes - JSON parsed attributes of the response's body
|
175
|
+
|
176
|
+
def api(method, attributes, options = {})
|
177
|
+
prefix = options.fetch(:prefix, default_prefix)
|
178
|
+
attributes = { prefix => attributes } unless prefix.empty? or attributes.empty?
|
179
|
+
uri = options.fetch(:uri, default_uri)
|
180
|
+
|
181
|
+
logger.debug do
|
182
|
+
"==> #{method.upcase} #{uri} [#{attributes}]"
|
183
|
+
end
|
184
|
+
|
185
|
+
before = Time.now
|
186
|
+
response = api_http method, uri, attributes
|
187
|
+
after = Time.now
|
188
|
+
|
189
|
+
ok = status_ok? method, uri, response
|
190
|
+
|
191
|
+
response_json = begin
|
192
|
+
api_parse_json(response)
|
193
|
+
rescue JSONError => e
|
194
|
+
logger.error do
|
195
|
+
"#{api_response_inspect(method, uri, response, '', after, before)} - #{e.message}"
|
196
|
+
end
|
197
|
+
raise e
|
198
|
+
end
|
199
|
+
|
200
|
+
ret = { response: response, response_json: response_json, ok: ok }
|
201
|
+
|
202
|
+
logger.debug do
|
203
|
+
api_response_inspect(method, uri, response, response_json, after, before)
|
204
|
+
end
|
205
|
+
|
206
|
+
if ok
|
207
|
+
prefix = options.fetch(:rprefix, prefix)
|
208
|
+
attributes = response_json.fetch(prefix, nil) unless prefix.empty?
|
209
|
+
|
210
|
+
ret[:object] = if attributes and options[:build]
|
211
|
+
new attributes
|
212
|
+
else
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
else
|
216
|
+
# something went wrong. let's either let the user fix it, and ask him to provide us
|
217
|
+
# with directions returned from block or just use :raise
|
218
|
+
do_raise = if block_given?
|
219
|
+
yield(ret)
|
220
|
+
else
|
221
|
+
options.fetch(:raise, true)
|
222
|
+
end
|
223
|
+
raise APIError.new(method, uri, response, response_json) if do_raise
|
224
|
+
end
|
225
|
+
|
226
|
+
ret[:attributes] = attributes
|
227
|
+
ret
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
module APIClient
|
4
|
+
Error = Class.new StandardError
|
5
|
+
|
6
|
+
class APIError < Error
|
7
|
+
attr_reader :method, :uri, :response, :attributes
|
8
|
+
|
9
|
+
def initialize(method, uri, response, attributes)
|
10
|
+
@method, @uri, @response, @attributes = method, uri, response, attributes
|
11
|
+
super "#{self.class}: #{response.status} #{method.upcase} #{uri}, attributes:" \
|
12
|
+
" #{attributes.inspect}, response.body: #{response.body[0,256]}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class APIServerError < APIError
|
17
|
+
def initialize(method, uri, response, attributes = {})
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
APIInternalServerError = Class.new APIServerError
|
23
|
+
APIBadGatewayError = Class.new APIServerError
|
24
|
+
APIServiceUnavailableError = Class.new APIServerError
|
25
|
+
|
26
|
+
class ConnectionError < Error
|
27
|
+
def initialize(error)
|
28
|
+
super "#{self.class}: #{error.message}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class JSONError < Error
|
33
|
+
def initialize(error)
|
34
|
+
msg = error.respond_to?(:message) ? error.message : error
|
35
|
+
super "#{self.class}: #{msg[0,512]}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Resource
|
40
|
+
|
41
|
+
include Attributes
|
42
|
+
include Support
|
43
|
+
include Operations
|
44
|
+
|
45
|
+
def initialize(attributes)
|
46
|
+
update_attributes(attributes)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
module APIClient
|
4
|
+
module Support
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def status_ok?(method, uri, response)
|
11
|
+
status = response.status
|
12
|
+
# handle server errors here, since we will not be expecting JSON
|
13
|
+
raise internal_api_error(status).new(method, uri, response) if status >= 500
|
14
|
+
case method
|
15
|
+
when :post then [200, 201]
|
16
|
+
when :put then [200, 204, 202]
|
17
|
+
when :delete then [200, 204, 202]
|
18
|
+
else [200]
|
19
|
+
end.include? status
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_json(body)
|
23
|
+
JSON.parse(body, symbolize_names: true)
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_uri(uri = nil)
|
27
|
+
return @default_uri ||= "/internal/#{self.to_s.split(':').last.downcase!}s/" unless uri
|
28
|
+
@default_uri = uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_http_error_exception(exception = nil)
|
32
|
+
return @default_http_error_exception ||= APIError unless exception
|
33
|
+
@default_http_error_exception = exception
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_prefix(prefix = nil)
|
37
|
+
return @default_prefix ||= self.to_s.split(':').last.downcase.to_sym unless prefix
|
38
|
+
@default_prefix = prefix
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def internal_api_error(status)
|
44
|
+
case status
|
45
|
+
when 503 then APIServiceUnavailableError
|
46
|
+
when 502 then APIBadGatewayError
|
47
|
+
when 500 then APIInternalServerError
|
48
|
+
else APIServerError
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
class Application < APIClient::Resource
|
4
|
+
## added the :user_required to distinguish between types of application:
|
5
|
+
## false is the default value, do not expect user_id or ignore it if it happends
|
6
|
+
## true, the user_id must be defined + the user of the service (service_id#user_id),
|
7
|
+
## user_id is typically the UUID of a cellphone, or the twitter account
|
8
|
+
attributes :service_id, :id, :state, :plan_id, :plan_name,
|
9
|
+
:redirect_url, :user_required
|
10
|
+
|
11
|
+
default_uri '/internal/services/'
|
12
|
+
|
13
|
+
def self.base_uri(service_id)
|
14
|
+
"#{default_uri}#{service_id}/applications/"
|
15
|
+
end
|
16
|
+
private_class_method :base_uri
|
17
|
+
|
18
|
+
def self.app_uri(service_id, id)
|
19
|
+
"#{base_uri(service_id)}#{id}"
|
20
|
+
end
|
21
|
+
private_class_method :app_uri
|
22
|
+
|
23
|
+
def self.key_uri(service_id, key)
|
24
|
+
"#{base_uri(service_id)}key/#{key}"
|
25
|
+
end
|
26
|
+
private_class_method :key_uri
|
27
|
+
|
28
|
+
def self.load(service_id, id)
|
29
|
+
api_read({}, uri: app_uri(service_id, id))
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.save(attributes)
|
33
|
+
service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
|
34
|
+
api_update attributes, uri: app_uri(service_id, id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.delete(service_id, id)
|
38
|
+
api_delete({}, uri: app_uri(service_id, id))
|
39
|
+
end
|
40
|
+
|
41
|
+
def save
|
42
|
+
api_save uri: self.class.send(:app_uri, service_id, id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def user_required?
|
46
|
+
user_required
|
47
|
+
end
|
48
|
+
|
49
|
+
# XXX Old API. Just returns an id. DEPRECATED.
|
50
|
+
def self.load_id_by_key(service_id, user_key)
|
51
|
+
ret = api_do_get({}, uri: key_uri(service_id, user_key))
|
52
|
+
ret[:ok] ? ret[:attributes][:id] : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.save_id_by_key(service_id, user_key, id)
|
56
|
+
raise ApplicationHasInconsistentData.new(id, user_key) if (service_id.nil? || id.nil? || user_key.nil? || service_id=="" || id=="" || user_key=="")
|
57
|
+
ret = api_do_put({}, uri: "#{app_uri(service_id, id)}/key/#{user_key}")
|
58
|
+
ret[:ok]
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.delete_id_by_key(service_id, user_key)
|
62
|
+
api_delete({}, uri: key_uri(service_id, user_key))
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
class ApplicationKey < APIClient::Resource
|
4
|
+
attributes :service_id, :application_id, :value
|
5
|
+
|
6
|
+
default_uri '/internal/services/'
|
7
|
+
|
8
|
+
def self.load_all(service_id, application_id)
|
9
|
+
results = api_do_get({}, rprefix: :application_keys, uri: application_key_uri(service_id, application_id))
|
10
|
+
return [] if results[:attributes].is_a?(Hash) && results[:attributes][:error]
|
11
|
+
|
12
|
+
results[:attributes].map { |attrs| new(attrs) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.save(service_id, application_id, value)
|
16
|
+
api_save({value: value}, uri: application_key_uri(service_id, application_id), prefix: :application_key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.delete(service_id, application_id, value)
|
20
|
+
api_delete({}, uri: application_key_uri(service_id, application_id, value))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.base_uri(service_id, application_id)
|
24
|
+
"#{default_uri}#{service_id}/applications/#{application_id}/keys/"
|
25
|
+
end
|
26
|
+
private_class_method :base_uri
|
27
|
+
|
28
|
+
def self.application_key_uri(service_id, application_id, value = nil)
|
29
|
+
"#{base_uri(service_id, application_id)}#{value}"
|
30
|
+
end
|
31
|
+
private_class_method :application_key_uri
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module ThreeScale
|
4
|
+
module Core
|
5
|
+
class ApplicationReferrerFilter < APIClient::Resource
|
6
|
+
default_uri '/internal/services/'
|
7
|
+
|
8
|
+
def self.load_all(service_id, application_id)
|
9
|
+
results = api_do_get({},
|
10
|
+
rprefix: :referrer_filters,
|
11
|
+
uri: base_uri(service_id, application_id))
|
12
|
+
results[:attributes]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.save(service_id, application_id, value)
|
16
|
+
result = api_do_post({ referrer_filter: value },
|
17
|
+
uri: base_uri(service_id, application_id),
|
18
|
+
prefix: '')
|
19
|
+
result[:response_json][:referrer_filter]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.delete(service_id, application_id, value)
|
23
|
+
encoded_value = Base64.urlsafe_encode64(value)
|
24
|
+
api_delete({}, uri: base_uri(service_id, application_id) + "/#{encoded_value}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.base_uri(service_id, application_id)
|
28
|
+
"#{default_uri}#{service_id}/applications/#{application_id}/referrer_filters"
|
29
|
+
end
|
30
|
+
private_class_method :base_uri
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
class UnknownAPIEndpoint < RuntimeError; end
|
4
|
+
|
5
|
+
class Error < RuntimeError
|
6
|
+
def to_xml(options = {})
|
7
|
+
xml = Builder::XmlMarkup.new
|
8
|
+
xml.instruct! unless options[:skip_instruct]
|
9
|
+
xml.error(message, :code => code)
|
10
|
+
|
11
|
+
xml.target!
|
12
|
+
end
|
13
|
+
|
14
|
+
def code
|
15
|
+
self.class.code
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.code
|
19
|
+
underscore(name[/[^:]*$/])
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: move this over to some utility module.
|
23
|
+
def self.underscore(string)
|
24
|
+
# Code stolen from ActiveSupport
|
25
|
+
string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
26
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
27
|
+
downcase
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
NotFound = Class.new(Error)
|
32
|
+
Invalid = Class.new(Error)
|
33
|
+
|
34
|
+
class ApplicationHasInconsistentData < Error
|
35
|
+
def initialize(id, user_key)
|
36
|
+
super %(Application id="#{id}" with user_key="#{user_key}" has inconsistent data and could not be saved)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ServiceRequiresDefaultUserPlan < Error
|
41
|
+
def initialize
|
42
|
+
super %(Services without the need for registered users require a default user plan)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ServiceIsDefaultService < Error
|
47
|
+
def initialize(id = nil)
|
48
|
+
super %(Service id="#{id}" is the default service, must be removed forcefully or make it not default before removal)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ServiceRequiresRegisteredUser < Error
|
53
|
+
def initialize(id = nil)
|
54
|
+
super %(Service id="#{id}" requires users to be registered before hand)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class UserRequiresUsername < Error
|
59
|
+
def initialize
|
60
|
+
super %(User requires username)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class UserRequiresServiceId < Error
|
65
|
+
def initialize
|
66
|
+
super %(User requires a service id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class UserRequiresValidServiceId < Error
|
71
|
+
def initialize(id)
|
72
|
+
super %(Service id #{id} is invalid, user requires a valid id)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class UserRequiresDefinedPlan < Error
|
77
|
+
def initialize(plan_id, plan_name)
|
78
|
+
super %(User requires a defined plan, plan id: #{plan_id} plan name: #{plan_name})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class InvalidProviderKeys < Error
|
83
|
+
def initialize
|
84
|
+
super %(Provider keys are not valid, must be not nil and different)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class ProviderKeyExists < Error
|
89
|
+
def initialize(key)
|
90
|
+
super %(Provider key="#{key}" already exists)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class ProviderKeyNotFound < Error
|
95
|
+
def initialize(key)
|
96
|
+
super %(Provider key="#{key}" does not exist)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class UsageLimitInvalidPeriods < Error
|
101
|
+
def initialize(periods)
|
102
|
+
super %(UsageLimit invalid periods #{periods})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class InvalidPerPage < Error
|
107
|
+
def initialize
|
108
|
+
super %(per_page is not valid, must be positive)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class ServiceTokenRequiresServiceId < Error
|
113
|
+
def initialize
|
114
|
+
super 'ServiceToken is invalid, service ID cannot be blank'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class ServiceTokenRequiresToken < Error
|
119
|
+
def initialize
|
120
|
+
super 'ServiceToken is invalid, token cannot be blank'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class ServiceTokenMissingParameter < Error
|
125
|
+
def initialize(error_text)
|
126
|
+
super %(ServiceToken is invalid, #{error_text})
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
class Event < APIClient::Resource
|
4
|
+
attributes :id, :type, :timestamp, :object
|
5
|
+
|
6
|
+
def self.load_all
|
7
|
+
results = api_do_get({}, rprefix: :events)
|
8
|
+
results[:attributes].map { |attrs| new attrs }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.delete(id)
|
12
|
+
api_delete({}, uri: event_uri(id))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.delete_upto(id)
|
16
|
+
results = api_do_delete({ upto_id: id }, prefix: '')
|
17
|
+
results[:response_json][:num_events]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.event_uri(id)
|
21
|
+
"#{default_uri}#{id}"
|
22
|
+
end
|
23
|
+
private_class_method :event_uri
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Core
|
3
|
+
class Metric < APIClient::Resource
|
4
|
+
attributes :service_id, :id, :parent_id, :name
|
5
|
+
|
6
|
+
default_uri '/internal/services/'
|
7
|
+
|
8
|
+
def self.base_uri(service_id)
|
9
|
+
"#{default_uri}#{service_id}/metrics/"
|
10
|
+
end
|
11
|
+
private_class_method :base_uri
|
12
|
+
|
13
|
+
def self.metric_uri(service_id, id)
|
14
|
+
"#{base_uri(service_id)}#{id}"
|
15
|
+
end
|
16
|
+
private_class_method :metric_uri
|
17
|
+
|
18
|
+
def self.load(service_id, id)
|
19
|
+
api_read({}, uri: metric_uri(service_id, id))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.save(attributes)
|
23
|
+
service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
|
24
|
+
api_update attributes, uri: metric_uri(service_id, id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.delete(service_id, id)
|
28
|
+
api_delete({}, uri: metric_uri(service_id, id))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|