apigee-platform 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +15 -0
- data/Gemfile.lock +96 -0
- data/LICENSE.txt +20 -0
- data/README.md +173 -0
- data/Rakefile +44 -0
- data/lib/apigee-platform.rb +5 -0
- data/lib/apigee-platform/associations.rb +70 -0
- data/lib/apigee-platform/custom_attributes.rb +34 -0
- data/lib/apigee-platform/objects/api.rb +11 -0
- data/lib/apigee-platform/objects/apiproduct.rb +10 -0
- data/lib/apigee-platform/objects/app.rb +11 -0
- data/lib/apigee-platform/objects/base.rb +88 -0
- data/lib/apigee-platform/objects/company.rb +13 -0
- data/lib/apigee-platform/objects/company_app.rb +17 -0
- data/lib/apigee-platform/objects/company_app_key.rb +7 -0
- data/lib/apigee-platform/objects/developer.rb +20 -0
- data/lib/apigee-platform/objects/developer_app.rb +17 -0
- data/lib/apigee-platform/objects/developer_app_key.rb +7 -0
- data/lib/apigee-platform/objects/key.rb +49 -0
- data/lib/apigee-platform/version.rb +10 -0
- data/spec/associations_spec.rb +130 -0
- data/spec/custom_attributes_spec.rb +34 -0
- data/spec/objects/developer_app_key_spec.rb +112 -0
- data/spec/objects/developer_spec.rb +72 -0
- data/spec/spec_helper.rb +17 -0
- metadata +234 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
module ApigeePlatform::Objects
|
2
|
+
class Base < ActiveResource::Base
|
3
|
+
include ApigeePlatform::Associations
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
super(*args)
|
7
|
+
@id = self.attributes[self.class.primary_key]
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def custom_attributes
|
12
|
+
@custom_attributes ||= ApigeePlatform::CustomAttributes.new(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode(options={})
|
16
|
+
super options.merge(:root => false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(*args)
|
20
|
+
super(*args)
|
21
|
+
self.attributes['attributes'].map!{|r| {'name' => r.name, 'value' => r.value}} if self.attributes['attributes']
|
22
|
+
|
23
|
+
self.class.prefix_options.each do |k,v|
|
24
|
+
self.prefix_options[k] = self.attributes[v]
|
25
|
+
end
|
26
|
+
self.onload if self.respond_to?(:onload)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def id
|
31
|
+
# need that to get correct element_path when update resource object
|
32
|
+
@id ||= self.attributes[self.class.primary_key]
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
attr_reader :config
|
37
|
+
|
38
|
+
def configure(config)
|
39
|
+
@config = config.symbolize_keys.slice(:user, :password, :organization, :url)
|
40
|
+
@config[:url] ||= 'https://api.enterprise.apigee.com'
|
41
|
+
|
42
|
+
self.site = @config[:url] + '/v1/o/' + @config[:organization]
|
43
|
+
self.user = @config[:user]
|
44
|
+
self.password = @config[:password]
|
45
|
+
|
46
|
+
require 'apigee-platform/objects/api'
|
47
|
+
require 'apigee-platform/objects/apiproduct'
|
48
|
+
require 'apigee-platform/objects/app'
|
49
|
+
require 'apigee-platform/objects/key'
|
50
|
+
require 'apigee-platform/objects/company'
|
51
|
+
require 'apigee-platform/objects/company_app'
|
52
|
+
require 'apigee-platform/objects/company_app_key'
|
53
|
+
require 'apigee-platform/objects/developer'
|
54
|
+
require 'apigee-platform/objects/developer_app'
|
55
|
+
require 'apigee-platform/objects/developer_app_key'
|
56
|
+
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_prefix_options(options)
|
61
|
+
@prefix_options = options
|
62
|
+
end
|
63
|
+
|
64
|
+
def prefix_options
|
65
|
+
@prefix_options || []
|
66
|
+
end
|
67
|
+
|
68
|
+
def instantiate_record(record, prefix_options = {})
|
69
|
+
return record unless record.is_a?(Hash)
|
70
|
+
super(record, prefix_options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def collection_path(prefix_options = {}, query_options = nil)
|
74
|
+
check_prefix_options(prefix_options)
|
75
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
76
|
+
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def element_path(id, prefix_options = {}, query_options = nil)
|
80
|
+
check_prefix_options(prefix_options)
|
81
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
82
|
+
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ApigeePlatform::Objects
|
2
|
+
class CompanyApp < App
|
3
|
+
set_primary_key :name
|
4
|
+
set_prefix_options :company_name => :companyName
|
5
|
+
|
6
|
+
self.site = self.site.to_s + "/companies/:company_name"
|
7
|
+
validates_presence_of :name
|
8
|
+
|
9
|
+
belongs_to :company, :key => :companyName
|
10
|
+
has_many :keys, :through => :credentials
|
11
|
+
|
12
|
+
def self.element_name
|
13
|
+
'app'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ApigeePlatform::Objects
|
2
|
+
class Developer < Base
|
3
|
+
|
4
|
+
schema do
|
5
|
+
string 'name', 'email', 'firstName', 'lastName', 'userName', 'organizationName', 'status'
|
6
|
+
end
|
7
|
+
|
8
|
+
set_primary_key :developerId
|
9
|
+
|
10
|
+
validates_presence_of :firstName, :lastName, :userName, :email
|
11
|
+
validates_format_of :email, :with => /\A(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})\Z/i
|
12
|
+
|
13
|
+
has_many :apps
|
14
|
+
|
15
|
+
def id
|
16
|
+
developerId || email
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ApigeePlatform::Objects
|
2
|
+
class DeveloperApp < App
|
3
|
+
set_primary_key :name
|
4
|
+
set_prefix_options :developer_id => :developerId
|
5
|
+
|
6
|
+
self.site = self.site.to_s + "/developers/:developer_id"
|
7
|
+
|
8
|
+
validates_presence_of :name
|
9
|
+
belongs_to :developer
|
10
|
+
has_many :keys, :through => :credentials
|
11
|
+
|
12
|
+
def self.element_name
|
13
|
+
'app'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ApigeePlatform::Objects
|
2
|
+
#abstract class, describes behavior of api keys, nested in developer_app and company_app
|
3
|
+
class Key < Base
|
4
|
+
def self.element_name
|
5
|
+
'key'
|
6
|
+
end
|
7
|
+
|
8
|
+
def approve
|
9
|
+
connection.post element_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_product(product_name)
|
13
|
+
unless apiproducts[product_name]
|
14
|
+
connection.post element_path, {
|
15
|
+
:apiProducts => apiproducts.keys + [product_name]
|
16
|
+
}.to_json
|
17
|
+
apiproducts[product_name] = 'pending'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def approve_product(product_name)
|
22
|
+
return false unless apiproducts[product_name]
|
23
|
+
connection.post "#{element_path}/apiproducts/#{product_name}?action=approve", '', {'Content-Type' => 'application/octet-stream'}
|
24
|
+
apiproducts[product_name] = 'approved'
|
25
|
+
end
|
26
|
+
|
27
|
+
def revoke_product(product_name)
|
28
|
+
return false unless apiproducts[product_name]
|
29
|
+
connection.post "#{element_path}/apiproducts/#{product_name}?action=revoke", '', {'Content-Type' => 'application/octet-stream'}
|
30
|
+
apiproducts[product_name] = 'revoked'
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_product(product_name)
|
34
|
+
return false unless apiproducts[product_name]
|
35
|
+
connection.delete "#{element_path}/apiproducts/#{product_name}"
|
36
|
+
apiproducts.delete(product_name)
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def apiproducts
|
41
|
+
self.attributes['apiProducts']
|
42
|
+
end
|
43
|
+
|
44
|
+
def onload
|
45
|
+
self.attributes['apiProducts'] = self.attributes['apiProducts'].inject({}){|res, el| res[el.apiproduct] = el.status; res }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class MortalKombat
|
4
|
+
include ApigeePlatform::Associations
|
5
|
+
attr_accessor :mk_id
|
6
|
+
has_many :characters
|
7
|
+
|
8
|
+
def self.primary_key
|
9
|
+
:mk_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find(*args)
|
13
|
+
x = self.new
|
14
|
+
x.mk_id = 9
|
15
|
+
if args.first == :all
|
16
|
+
[x]
|
17
|
+
else
|
18
|
+
x
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MortalKombatCharacter
|
24
|
+
include ApigeePlatform::Associations
|
25
|
+
attr_accessor :char_id, :mk_id
|
26
|
+
|
27
|
+
belongs_to :mortal_kombat
|
28
|
+
has_many :locations, :through => 'maps'
|
29
|
+
|
30
|
+
def initialize(*args)
|
31
|
+
@params = args
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.prefix_options
|
35
|
+
{:version => :mk_id}
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.find(*args)
|
39
|
+
x = self.new
|
40
|
+
x.char_id = 'Jax'
|
41
|
+
if args.first == :all
|
42
|
+
[x]
|
43
|
+
else
|
44
|
+
x
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def maps
|
49
|
+
[
|
50
|
+
OpenStruct.new(:attributes => {:name => 'Kuatan'}),
|
51
|
+
OpenStruct.new(:attributes => {:name => 'Street'}),
|
52
|
+
OpenStruct.new(:attributes => {:name => 'Swamp'})]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class MortalKombatCharacterLocation
|
57
|
+
attr_accessor :name
|
58
|
+
def initialize(params, prefix_params={})
|
59
|
+
params.each{|k,v| instance_variable_set("@#{k}", v)}
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.prefix_options
|
63
|
+
{:char_id => :char_id}
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.instantiate_record(params, prefix_params={})
|
67
|
+
self.new(params, prefix_params)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
describe 'class with has_many association' do
|
73
|
+
subject { MortalKombat.new }
|
74
|
+
it 'can find all nested objects' do
|
75
|
+
subject.should respond_to(:characters)
|
76
|
+
subject.characters.should be_kind_of(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'has method to find subobject' do
|
80
|
+
subject.should respond_to(:character)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'is able to find subobject' do
|
84
|
+
subject.character('Jax').should be_kind_of(MortalKombatCharacter)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'return children' do
|
88
|
+
subject.characters.first.should be_kind_of(MortalKombatCharacter)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'can create subobject by getting requesting object without id' do
|
92
|
+
subject.character.should be_kind_of(MortalKombatCharacter)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'has method for creating subobject' do
|
96
|
+
subject.create_character.should be_kind_of(MortalKombatCharacter)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sets prefix parameters for subobject' do
|
100
|
+
subject.instance_variable_set(:@mk_id, 10)
|
101
|
+
pp = subject.create_character.instance_variable_get(:@params)
|
102
|
+
pp.should include({:mk_id=>10})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'class with belongs_to association' do
|
107
|
+
subject { MortalKombatCharacter.new }
|
108
|
+
it 'has method to get parent' do
|
109
|
+
subject.should respond_to(:mortal_kombat)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'return object of correct class when getting parent' do
|
113
|
+
subject.mortal_kombat.should be_kind_of(MortalKombat)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'class with belongs_to(:through => ..) association' do
|
119
|
+
subject { MortalKombatCharacter.new }
|
120
|
+
it 'has method to nested collection' do
|
121
|
+
subject.should respond_to(:locations)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'returns nested objects from method passed in \'through\' ' do
|
125
|
+
subject.locations.count.should == subject.maps.count
|
126
|
+
subject.locations.map(&:name).to_set.should == subject.maps.map{|el| el.attributes[:name]}.to_set
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe 'custom attrs' do
|
4
|
+
it 'make data accessible as hash elements' do
|
5
|
+
obj = OpenStruct.new :attributes => {'attributes' => [{'name' => 'name', 'value' => 'Kitana'}]}
|
6
|
+
c = ApigeePlatform::CustomAttributes.new obj
|
7
|
+
c['name'].should == obj.attributes['attributes'].first['value']
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'sets new values in source object' do
|
11
|
+
obj = OpenStruct.new :attributes => {'attributes' => []}
|
12
|
+
c = ApigeePlatform::CustomAttributes.new obj
|
13
|
+
c['name'] = 'Johnny Cage'
|
14
|
+
obj.attributes['attributes'].first['name'].should == 'name'
|
15
|
+
obj.attributes['attributes'].first['value'].should == 'Johnny Cage'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'return names of data variables' do
|
19
|
+
obj = OpenStruct.new :attributes => {'attributes' => [
|
20
|
+
{'name' => 'world', 'value' => 'MK'},
|
21
|
+
{'name' => 'fighter', 'value' => 'Kano'}
|
22
|
+
]}
|
23
|
+
c = ApigeePlatform::CustomAttributes.new obj
|
24
|
+
c.keys.to_set.should == ["world", "fighter"].to_set
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can delete data from source object' do
|
28
|
+
obj = OpenStruct.new :attributes => {'attributes' => [{'name' => 'name', 'value' => 'Kitana'}]}
|
29
|
+
c = ApigeePlatform::CustomAttributes.new obj
|
30
|
+
c.delete('name')
|
31
|
+
obj.attributes['attributes'].should be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe 'DeveloperAppKey' do
|
5
|
+
before :all do
|
6
|
+
@app_name = 'testapp'
|
7
|
+
@developer_email = 'sampledev@example.com'
|
8
|
+
@developer_id = 'F1bPGroWVtO9PATt'
|
9
|
+
@apiproduct_name = 'myapiproduct'
|
10
|
+
@new_apiproduct_name = 'mytest'
|
11
|
+
@consumer_key = 'OOdAwgpyifxXPUeMDGKJBqDDDfDK12AS'
|
12
|
+
@credentials = [
|
13
|
+
{
|
14
|
+
"apiProducts" => [{"apiproduct" => @apiproduct_name, "status" => "approved"}],
|
15
|
+
"attributes" => [],
|
16
|
+
"consumerKey" => @consumer_key,
|
17
|
+
"consumerSecret" => "lkECj1mAUzfBmdtD",
|
18
|
+
"scopes" => [],
|
19
|
+
"status" => "approved"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
@app = {
|
23
|
+
:name => @app_name,
|
24
|
+
:appId => '35eaba24-c340-48a2-819e-34d81993f9ab',
|
25
|
+
:developerId => @developer_id,
|
26
|
+
|
27
|
+
:accessType => "read",
|
28
|
+
:appFamily => "default",
|
29
|
+
:attributes => [{"name"=>"Developer", "value"=>@developer_email}, {"name"=>"DisplayName", "value"=>@app_name}, {"name"=>"Notes", "value"=>""}, {"name"=>"lastModifier", "value"=>""}],
|
30
|
+
:callbackUrl => "http://example.com",
|
31
|
+
:createdAt => 1369488501956,
|
32
|
+
:createdBy => "adminui@apigee.com",
|
33
|
+
:credentials => @credentials,
|
34
|
+
:lastModifiedAt => 1369555151917,
|
35
|
+
:lastModifiedBy => @developer_email,
|
36
|
+
:scopes => [],
|
37
|
+
:status => "approved"
|
38
|
+
}
|
39
|
+
|
40
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
41
|
+
org = ApigeePlatform::Objects::Base.config[:organization]
|
42
|
+
mock.get "/v1/o/#{org}/developers/#{@developer_id}/apps/#{@app_name}", GET_HEADERS, @app.to_json
|
43
|
+
mock.post "/v1/o/#{org}/developers/#{@developer_id}/apps/#{@app_name}/keys/#{@consumer_key}", POST_HEADERS, {"apiProducts"=>["smtp_public_api", @new_apiproduct_name]}.to_json
|
44
|
+
mock.post "/v1/o/#{org}/developers/#{@developer_id}/apps/#{@app_name}/keys/#{@consumer_key}/apiproducts/mytest?action=approve", NO_CONTENT_HEADERS, nil, 204
|
45
|
+
mock.post "/v1/o/#{org}/developers/#{@developer_id}/apps/#{@app_name}/keys/#{@consumer_key}/apiproducts/mytest?action=revoke", NO_CONTENT_HEADERS, nil, 204
|
46
|
+
mock.delete "/v1/o/#{org}/developers/#{@developer_id}/apps/#{@app_name}/keys/#{@consumer_key}/apiproducts/mytest", GET_HEADERS, nil, 204
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { ApigeePlatform::Objects::DeveloperApp.find(@app_name, :params => {:developer_id => @developer_id}) }
|
51
|
+
|
52
|
+
it 'has keys' do
|
53
|
+
subject.should respond_to(:keys)
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'Key' do
|
57
|
+
subject { ApigeePlatform::Objects::DeveloperApp.find(@app_name, :params => {:developer_id => @developer_id}).keys.first }
|
58
|
+
it 'has api products from nested credentials' do
|
59
|
+
subject.apiproducts[@credentials.first['apiProducts'].first['apiproduct']].should == @credentials.first['apiProducts'].first['status']
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'can add product' do
|
63
|
+
subject.should respond_to(:add_product)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can approve product' do
|
67
|
+
subject.should respond_to(:approve_product)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'can revoke product' do
|
71
|
+
subject.should respond_to(:revoke_product)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can remove product' do
|
75
|
+
subject.should respond_to(:remove_product)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'saves new product' do
|
79
|
+
subject.add_product(@new_apiproduct_name)
|
80
|
+
subject.apiproducts[@new_apiproduct_name].should be_present
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'saves new product' do
|
84
|
+
subject.add_product(@new_apiproduct_name)
|
85
|
+
subject.apiproducts[@new_apiproduct_name].should be_present
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'approves product' do
|
89
|
+
subject.add_product(@new_apiproduct_name)
|
90
|
+
subject.approve_product(@new_apiproduct_name)
|
91
|
+
subject.apiproducts[@new_apiproduct_name].should == 'approved'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'revokes product' do
|
95
|
+
subject.add_product(@new_apiproduct_name)
|
96
|
+
subject.revoke_product(@new_apiproduct_name)
|
97
|
+
subject.apiproducts[@new_apiproduct_name].should == 'revoked'
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'removes product' do
|
101
|
+
subject.add_product(@new_apiproduct_name)
|
102
|
+
subject.remove_product(@new_apiproduct_name)
|
103
|
+
subject.apiproducts[@new_apiproduct_name].should_not be_present
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|