apigee-platform 0.0.2
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.
- 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
|
+
|