pisoni 1.23.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|