amee 2.0.25
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +19 -0
- data/README +106 -0
- data/amee.example.yml +12 -0
- data/bin/ameesh +30 -0
- data/examples/create_profile.rb +27 -0
- data/examples/create_profile_item.rb +33 -0
- data/examples/list_profiles.rb +29 -0
- data/examples/view_data_category.rb +40 -0
- data/examples/view_data_item.rb +37 -0
- data/init.rb +1 -0
- data/lib/amee.rb +63 -0
- data/lib/amee/connection.rb +236 -0
- data/lib/amee/data_category.rb +196 -0
- data/lib/amee/data_item.rb +218 -0
- data/lib/amee/data_item_value.rb +167 -0
- data/lib/amee/data_object.rb +11 -0
- data/lib/amee/drill_down.rb +102 -0
- data/lib/amee/exceptions.rb +27 -0
- data/lib/amee/item_definition.rb +158 -0
- data/lib/amee/object.rb +21 -0
- data/lib/amee/pager.rb +59 -0
- data/lib/amee/profile.rb +108 -0
- data/lib/amee/profile_category.rb +514 -0
- data/lib/amee/profile_item.rb +374 -0
- data/lib/amee/profile_item_value.rb +106 -0
- data/lib/amee/profile_object.rb +20 -0
- data/lib/amee/rails.rb +82 -0
- data/lib/amee/shell.rb +90 -0
- data/lib/amee/user.rb +111 -0
- data/lib/amee/version.rb +10 -0
- data/rails/init.rb +12 -0
- metadata +104 -0
data/COPYING
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 James Smith (james@floppy.org.uk)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
== AMEE-Ruby
|
2
|
+
|
3
|
+
A gem to provide a Ruby interface to the AMEE carbon calculator (http://amee.cc)
|
4
|
+
|
5
|
+
Licensed under the MIT license (See COPYING file for details)
|
6
|
+
|
7
|
+
Author: James Smith (james@floppy.org.uk / http://www.floppy.org.uk)
|
8
|
+
|
9
|
+
Homepage: http://github.com/Floppy/amee-ruby
|
10
|
+
|
11
|
+
Documentation: http://docs.github.com/Floppy/amee-ruby
|
12
|
+
|
13
|
+
== INSTALLATION
|
14
|
+
|
15
|
+
1) Enable gems from github, if you haven't already done so (rubygems >= 1.2):
|
16
|
+
> sudo gem sources -a http://gems.github.com
|
17
|
+
|
18
|
+
2) Install gem
|
19
|
+
> sudo gem install Floppy-amee
|
20
|
+
|
21
|
+
== IMPORTANT CHANGES in 2.0.25
|
22
|
+
|
23
|
+
If you are using the $amee connection in your Rails apps, this is now deprecated
|
24
|
+
and will be removed in future releases. See the "Rails" section below for details
|
25
|
+
of what you should use instead.
|
26
|
+
|
27
|
+
== USAGE
|
28
|
+
|
29
|
+
Currently, you can read DataCategories, DataItems and DataItemValues. See
|
30
|
+
examples/view_data_*.rb for simple usage examples. You can also get the list
|
31
|
+
of available Profiles, and create and delete them. See examples/list_profiles.rb
|
32
|
+
and examples/create_profile.rb for details. You can also load ProfileCategories,
|
33
|
+
and load, create and update ProfileItems.
|
34
|
+
|
35
|
+
The gem will use the AMEE JSON API if the JSON gem is installed on the local
|
36
|
+
system. Otherwise the XML API will be used.
|
37
|
+
|
38
|
+
== SUPPORT
|
39
|
+
Create Read Update Delete
|
40
|
+
DataCategories N Y N N
|
41
|
+
DataItems N Y N N
|
42
|
+
DataItemValues N Y N Y
|
43
|
+
Profile List - Y - -
|
44
|
+
Profiles Y - - Y
|
45
|
+
ProfileCategories - Y - -
|
46
|
+
- drilldown - Y - -
|
47
|
+
ProfileItems Y Y Y Y
|
48
|
+
|
49
|
+
== INTERACTIVE SHELL
|
50
|
+
|
51
|
+
You can use the 'ameesh' app to interactively explore the AMEE data area. Run
|
52
|
+
'ameesh -u USERNAME -p PASSWORD -s SERVER' to try it out. Source code for this
|
53
|
+
tool is in bin/ameesh and lib/amee/shell.rb. Profiles are not accessible through
|
54
|
+
this interface yet.
|
55
|
+
|
56
|
+
== RAILS
|
57
|
+
|
58
|
+
This gem can also be used as a Rails plugin. You can either extract it into
|
59
|
+
vendor/plugins, or use the new-style config.gem command in environment.rb. For
|
60
|
+
example:
|
61
|
+
|
62
|
+
config.gem "Floppy-amee", :lib => "amee", :source => "http://gems.github.com", :version => '>= 0.3.0'
|
63
|
+
|
64
|
+
If you copy amee.example.yml from the gem source directory to amee.yml in your
|
65
|
+
app's config directory, a persistent AMEE connection will be available from
|
66
|
+
AMEE::Rails#connection, which you can use anywhere. In your controllers, you can
|
67
|
+
also use the global_amee_connection function to access the same global connection.
|
68
|
+
|
69
|
+
data = AMEE::Data::Category.root(global_amee_connection)
|
70
|
+
|
71
|
+
If you do not use this facility, you will have to create your own connection
|
72
|
+
objects and manage them yourself, which you can do using AMEE::Connection#new
|
73
|
+
|
74
|
+
There is a helper for ActiveRecord models which should be linked to an AMEE profile.
|
75
|
+
By adding:
|
76
|
+
|
77
|
+
has_amee_profile
|
78
|
+
|
79
|
+
to your model, and by adding an amee_profile:string field to the model in the
|
80
|
+
database, an AMEE profile will be automatically created and destroyed with your
|
81
|
+
model. By overriding the function amee_save in your model, you can store data in
|
82
|
+
AMEE when your model is saved.
|
83
|
+
|
84
|
+
== CACHING
|
85
|
+
|
86
|
+
The AMEE::Connection object implements an optional cache for GET requests. This is
|
87
|
+
currently a versy simple implementation which caches the result of all GET requests
|
88
|
+
until a POST, PUT, or DELETE is executed, at which point the cache is cleared. To
|
89
|
+
enable caching, set the enable_caching parameter of AMEE::Connection.new to true.
|
90
|
+
Caching is disabled by default.
|
91
|
+
|
92
|
+
== UPGRADING TO VERSION > 2
|
93
|
+
|
94
|
+
There are a few changes to the API exposed by this gem for version 2. The main
|
95
|
+
ones are:
|
96
|
+
|
97
|
+
1) AMEE::Connection#new takes a hash of options instead of an explicit parameter list.
|
98
|
+
Whereas before you would have used new(server, username, password, use_json, enable_cache, enable_debug)
|
99
|
+
you would now use new(server, username, password, :format => :json, :enable_caching => true, :enable_debug => true)
|
100
|
+
|
101
|
+
2) Many get functions take a hash of options instead of explicit date and itemsPerPage parameters.
|
102
|
+
get(... , :start_date => {your_date}, :itemsPerPage => 20)
|
103
|
+
|
104
|
+
3) total_amount_per_month functions have been replaced with total_amount. There are also
|
105
|
+
total_amount_unit and total_amount_per_unit functions which give the units that the total
|
106
|
+
amount is in.
|
data/amee.example.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
development:
|
2
|
+
server: stage.amee.com
|
3
|
+
username: your_amee_username
|
4
|
+
password: your_amee_password
|
5
|
+
test:
|
6
|
+
server: stage.amee.com
|
7
|
+
username: your_amee_username
|
8
|
+
password: your_amee_password
|
9
|
+
production:
|
10
|
+
server: live.amee.com
|
11
|
+
username: your_amee_username
|
12
|
+
password: your_amee_password
|
data/bin/ameesh
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
shell_lib = File.dirname(__FILE__) + '/../lib/amee/shell'
|
4
|
+
irb_name = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
# Command-line options - get username, password, and server
|
8
|
+
options = {}
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.on("-u USERNAME", "AMEE username") do |u|
|
11
|
+
options[:username] = u
|
12
|
+
end
|
13
|
+
opts.on("-p PASSWORD", "AMEE password") do |p|
|
14
|
+
options[:password] = p
|
15
|
+
end
|
16
|
+
opts.on("-s SERVER", "AMEE server") do |s|
|
17
|
+
options[:server] = s
|
18
|
+
end
|
19
|
+
end.parse!
|
20
|
+
|
21
|
+
# Set environment variables for irb
|
22
|
+
ENV['AMEE_SERVER'] = options[:server]
|
23
|
+
ENV['AMEE_USERNAME'] = options[:username]
|
24
|
+
ENV['AMEE_PASSWORD'] = options[:password]
|
25
|
+
|
26
|
+
if options[:server].nil? || options[:username].nil? || options[:password].nil?
|
27
|
+
puts "Please provide connection details. Run 'ameesh --help' for details."
|
28
|
+
else
|
29
|
+
exec "#{irb_name} -r #{shell_lib} --simple-prompt"
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
dir = File.dirname(__FILE__) + '/../lib'
|
2
|
+
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
|
3
|
+
|
4
|
+
#require 'rubygems'
|
5
|
+
require 'amee'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
# Command-line options - get username, password, and server
|
9
|
+
options = {}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.on("-u", "--username USERNAME", "AMEE username") do |u|
|
12
|
+
options[:username] = u
|
13
|
+
end
|
14
|
+
opts.on("-p", "--password PASSWORD", "AMEE password") do |p|
|
15
|
+
options[:password] = p
|
16
|
+
end
|
17
|
+
opts.on("-s", "--server SERVER", "AMEE server") do |s|
|
18
|
+
options[:server] = s
|
19
|
+
end
|
20
|
+
end.parse!
|
21
|
+
|
22
|
+
# Connect
|
23
|
+
connection = AMEE::Connection.new(options[:server], options[:username], options[:password])
|
24
|
+
|
25
|
+
# Create a new profile
|
26
|
+
profile = AMEE::Profile::Profile.create(connection)
|
27
|
+
puts "#{profile.uid} created"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
dir = File.dirname(__FILE__) + '/../lib'
|
2
|
+
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
|
3
|
+
|
4
|
+
#require 'rubygems'
|
5
|
+
require 'amee'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
# Command-line options - get username, password, and server
|
9
|
+
options = {}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.on("-u", "--username USERNAME", "AMEE username") do |u|
|
12
|
+
options[:username] = u
|
13
|
+
end
|
14
|
+
opts.on("-p", "--password PASSWORD", "AMEE password") do |p|
|
15
|
+
options[:password] = p
|
16
|
+
end
|
17
|
+
opts.on("-s", "--server SERVER", "AMEE server") do |s|
|
18
|
+
options[:server] = s
|
19
|
+
end
|
20
|
+
end.parse!
|
21
|
+
|
22
|
+
# Connect
|
23
|
+
connection = AMEE::Connection.new(options[:server], options[:username], options[:password])
|
24
|
+
|
25
|
+
# Create a new profile item
|
26
|
+
category = AMEE::Profile::Category.get(connection, ARGV[0])
|
27
|
+
puts "loaded category #{category.name}"
|
28
|
+
item = AMEE::Profile::Item.create(category, ARGV[1])
|
29
|
+
if item
|
30
|
+
puts "created item in #{category.name} OK"
|
31
|
+
else
|
32
|
+
puts "error creating item in #{category.name}"
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'amee'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# Command-line options - get username, password, and server
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.on("-u", "--username USERNAME", "AMEE username") do |u|
|
9
|
+
options[:username] = u
|
10
|
+
end
|
11
|
+
opts.on("-p", "--password PASSWORD", "AMEE password") do |p|
|
12
|
+
options[:password] = p
|
13
|
+
end
|
14
|
+
opts.on("-s", "--server SERVER", "AMEE server") do |s|
|
15
|
+
options[:server] = s
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
# Connect
|
20
|
+
connection = AMEE::Connection.new(options[:server], options[:username], options[:password])
|
21
|
+
|
22
|
+
# List all available profiles
|
23
|
+
profiles = AMEE::Profile::Profile.list(connection)
|
24
|
+
puts "#{profiles.size} #{profiles.size == 1 ? "profile" : "profiles"} available in AMEE:"
|
25
|
+
profiles.each do |p|
|
26
|
+
puts p.uid
|
27
|
+
end
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'amee'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# Command-line options - get username, password, and server
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.on("-u", "--username USERNAME", "AMEE username") do |u|
|
9
|
+
options[:username] = u
|
10
|
+
end
|
11
|
+
opts.on("-p", "--password PASSWORD", "AMEE password") do |p|
|
12
|
+
options[:password] = p
|
13
|
+
end
|
14
|
+
opts.on("-s", "--server SERVER", "AMEE server") do |s|
|
15
|
+
options[:server] = s
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
# Connect
|
20
|
+
connection = AMEE::Connection.new(options[:server], options[:username], options[:password])
|
21
|
+
|
22
|
+
# For each path in arg list, show details
|
23
|
+
ARGV.each do |path|
|
24
|
+
cat = AMEE::Data::Category.get(connection, path)
|
25
|
+
puts "---------------------"
|
26
|
+
puts "Category: #{cat.name}"
|
27
|
+
puts "Path: #{cat.full_path}"
|
28
|
+
puts "UID: #{cat.uid}"
|
29
|
+
puts "Subcategories:"
|
30
|
+
cat.children.each do |c|
|
31
|
+
puts " - #{c[:path]} (#{c[:name]})"
|
32
|
+
end
|
33
|
+
puts "Items:"
|
34
|
+
cat.items.each do |i|
|
35
|
+
puts " - #{i[:path]} (#{i[:label]})"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'amee'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# Command-line options - get username, password, and server
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.on("-u", "--username USERNAME", "AMEE username") do |u|
|
9
|
+
options[:username] = u
|
10
|
+
end
|
11
|
+
opts.on("-p", "--password PASSWORD", "AMEE password") do |p|
|
12
|
+
options[:password] = p
|
13
|
+
end
|
14
|
+
opts.on("-s", "--server SERVER", "AMEE server") do |s|
|
15
|
+
options[:server] = s
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
# Connect
|
20
|
+
connection = AMEE::Connection.new(options[:server], options[:username], options[:password])
|
21
|
+
|
22
|
+
# For each path in arg list, show details
|
23
|
+
ARGV.each do |path|
|
24
|
+
cat = AMEE::Data::Item.get(connection, path)
|
25
|
+
puts "---------------------"
|
26
|
+
puts "Name: #{cat.name}"
|
27
|
+
puts "Path: #{cat.full_path}"
|
28
|
+
puts "Label: #{cat.label}"
|
29
|
+
puts "UID: #{cat.uid}"
|
30
|
+
puts "Values:"
|
31
|
+
cat.values.each do |v|
|
32
|
+
puts " - #{v[:name]}: #{v[:value]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init"
|
data/lib/amee.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'activesupport'
|
3
|
+
|
4
|
+
# We don't NEED the JSON gem, but if it's available, use it.
|
5
|
+
begin
|
6
|
+
require 'json'
|
7
|
+
rescue LoadError
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
class String
|
12
|
+
def is_json?
|
13
|
+
slice(0,1) == '{'
|
14
|
+
end
|
15
|
+
def is_v2_json?
|
16
|
+
is_json? && match('"apiVersion"\s?:\s?"2.0"')
|
17
|
+
end
|
18
|
+
def is_xml?
|
19
|
+
slice(0,5) == '<?xml'
|
20
|
+
end
|
21
|
+
def is_v2_xml?
|
22
|
+
is_xml? && include?('<Resources xmlns="http://schemas.amee.cc/2.0">')
|
23
|
+
end
|
24
|
+
def is_v2_atom?
|
25
|
+
is_xml? && (include?('<feed ') || include?('<entry ')) && include?('xmlns:amee="http://schemas.amee.cc/2.0"')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'amee/version'
|
30
|
+
require 'amee/exceptions'
|
31
|
+
require 'amee/connection'
|
32
|
+
require 'amee/object'
|
33
|
+
require 'amee/data_object'
|
34
|
+
require 'amee/profile_object'
|
35
|
+
require 'amee/data_category'
|
36
|
+
require 'amee/data_item'
|
37
|
+
require 'amee/data_item_value'
|
38
|
+
require 'amee/profile'
|
39
|
+
require 'amee/profile_category'
|
40
|
+
require 'amee/profile_item'
|
41
|
+
require 'amee/profile_item_value'
|
42
|
+
require 'amee/drill_down'
|
43
|
+
require 'amee/pager'
|
44
|
+
require 'amee/item_definition'
|
45
|
+
require 'amee/user'
|
46
|
+
|
47
|
+
class Date
|
48
|
+
def amee1_date
|
49
|
+
strftime("%Y%m%d")
|
50
|
+
end
|
51
|
+
def amee1_month
|
52
|
+
strftime("%Y%m")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Time
|
57
|
+
def amee1_date
|
58
|
+
strftime("%Y%m%d")
|
59
|
+
end
|
60
|
+
def amee1_month
|
61
|
+
strftime("%Y%m")
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module AMEE
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
def initialize(server, username, password, options = {})
|
7
|
+
unless options.is_a?(Hash)
|
8
|
+
raise AMEE::ArgumentError.new("Fourth argument must be a hash of options!")
|
9
|
+
end
|
10
|
+
@server = server
|
11
|
+
@username = username
|
12
|
+
@password = password
|
13
|
+
@auth_token = nil
|
14
|
+
@format = options[:format] || (defined?(JSON) ? :json : :xml)
|
15
|
+
if !valid?
|
16
|
+
raise "You must supply connection details - server, username and password are all required!"
|
17
|
+
end
|
18
|
+
@enable_caching = options[:enable_caching]
|
19
|
+
if @enable_caching
|
20
|
+
$cache ||= {}
|
21
|
+
end
|
22
|
+
# Make connection to server
|
23
|
+
@http = Net::HTTP.new(@server)
|
24
|
+
@http.read_timeout = 5
|
25
|
+
@http.set_debug_output($stdout) if options[:enable_debug]
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :format
|
29
|
+
attr_reader :server
|
30
|
+
attr_reader :username
|
31
|
+
attr_reader :password
|
32
|
+
|
33
|
+
def timeout
|
34
|
+
@http.read_timeout
|
35
|
+
end
|
36
|
+
|
37
|
+
def timeout=(t)
|
38
|
+
@http.read_timeout = t
|
39
|
+
end
|
40
|
+
|
41
|
+
def version
|
42
|
+
authenticate if @version.nil?
|
43
|
+
@version
|
44
|
+
end
|
45
|
+
|
46
|
+
def valid?
|
47
|
+
@username && @password && @server
|
48
|
+
end
|
49
|
+
|
50
|
+
def authenticated?
|
51
|
+
!@auth_token.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def get(path, data = {})
|
55
|
+
# Allow format override
|
56
|
+
format = data.delete(:format) || @format
|
57
|
+
# Create URL parameters
|
58
|
+
params = []
|
59
|
+
data.each_pair do |key, value|
|
60
|
+
params << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
|
61
|
+
end
|
62
|
+
if params.size > 0
|
63
|
+
path += "?#{params.join('&')}"
|
64
|
+
end
|
65
|
+
# Send request
|
66
|
+
return $cache[path] if @enable_caching and $cache[path]
|
67
|
+
response = do_request(Net::HTTP::Get.new(path), format)
|
68
|
+
$cache[path] = response if @enable_caching
|
69
|
+
return response
|
70
|
+
end
|
71
|
+
|
72
|
+
def post(path, data = {})
|
73
|
+
# Allow format override
|
74
|
+
format = data.delete(:format) || @format
|
75
|
+
# Clear cache
|
76
|
+
clear_cache
|
77
|
+
# Create POST request
|
78
|
+
post = Net::HTTP::Post.new(path)
|
79
|
+
body = []
|
80
|
+
data.each_pair do |key, value|
|
81
|
+
body << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
|
82
|
+
end
|
83
|
+
post.body = body.join '&'
|
84
|
+
# Send request
|
85
|
+
do_request(post, format)
|
86
|
+
end
|
87
|
+
|
88
|
+
def raw_post(path, body, options = {})
|
89
|
+
# Allow format override
|
90
|
+
format = options.delete(:format) || @format
|
91
|
+
# Clear cache
|
92
|
+
clear_cache
|
93
|
+
# Create POST request
|
94
|
+
post = Net::HTTP::Post.new(path)
|
95
|
+
post['Content-type'] = options[:content_type] || content_type(format)
|
96
|
+
post.body = body
|
97
|
+
# Send request
|
98
|
+
do_request(post, format)
|
99
|
+
end
|
100
|
+
|
101
|
+
def put(path, data = {})
|
102
|
+
# Allow format override
|
103
|
+
format = data.delete(:format) || @format
|
104
|
+
# Clear cache
|
105
|
+
clear_cache
|
106
|
+
# Create PUT request
|
107
|
+
put = Net::HTTP::Put.new(path)
|
108
|
+
body = []
|
109
|
+
data.each_pair do |key, value|
|
110
|
+
body << "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}"
|
111
|
+
end
|
112
|
+
put.body = body.join '&'
|
113
|
+
# Send request
|
114
|
+
do_request(put, format)
|
115
|
+
end
|
116
|
+
|
117
|
+
def raw_put(path, body, options = {})
|
118
|
+
# Allow format override
|
119
|
+
format = options.delete(:format) || @format
|
120
|
+
# Clear cache
|
121
|
+
clear_cache
|
122
|
+
# Create PUT request
|
123
|
+
put = Net::HTTP::Put.new(path)
|
124
|
+
put['Content-type'] = options[:content_type] || content_type(format)
|
125
|
+
put.body = body
|
126
|
+
# Send request
|
127
|
+
do_request(put, format)
|
128
|
+
end
|
129
|
+
|
130
|
+
def delete(path)
|
131
|
+
clear_cache
|
132
|
+
# Create DELETE request
|
133
|
+
delete = Net::HTTP::Delete.new(path)
|
134
|
+
# Send request
|
135
|
+
do_request(delete)
|
136
|
+
end
|
137
|
+
|
138
|
+
def authenticate
|
139
|
+
response = nil
|
140
|
+
post = Net::HTTP::Post.new("/auth/signIn")
|
141
|
+
post.body = "username=#{@username}&password=#{@password}"
|
142
|
+
post['Accept'] = content_type(:xml)
|
143
|
+
response = @http.request(post)
|
144
|
+
@auth_token = response['authToken']
|
145
|
+
unless authenticated?
|
146
|
+
raise AMEE::AuthFailed.new("Authentication failed. Please check your username and password.")
|
147
|
+
end
|
148
|
+
# Detect API version
|
149
|
+
if response.body.is_json?
|
150
|
+
@version = JSON.parse(response.body)["user"]["apiVersion"].to_f
|
151
|
+
elsif response.body.is_xml?
|
152
|
+
@version = REXML::Document.new(response.body).elements['Resources'].elements['SignInResource'].elements['User'].elements['ApiVersion'].text.to_f
|
153
|
+
else
|
154
|
+
@version = 1.0
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
def content_type(format = @format)
|
161
|
+
case format
|
162
|
+
when :xml
|
163
|
+
return 'application/xml'
|
164
|
+
when :json
|
165
|
+
return 'application/json'
|
166
|
+
when :atom
|
167
|
+
return 'application/atom+xml'
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def redirect?(response)
|
172
|
+
response.code == '301' || response.code == '302'
|
173
|
+
end
|
174
|
+
|
175
|
+
def response_ok?(response)
|
176
|
+
case response.code
|
177
|
+
when '200', '201'
|
178
|
+
return true
|
179
|
+
when '403'
|
180
|
+
raise AMEE::PermissionDenied.new("You do not have permission to perform the requested operation. AMEE Response: #{response.body}")
|
181
|
+
when '401'
|
182
|
+
authenticate
|
183
|
+
return false
|
184
|
+
when '400'
|
185
|
+
if response.body.include? "would have resulted in a duplicate resource being created"
|
186
|
+
raise AMEE::DuplicateResource.new("The specified resource already exists. This is most often caused by creating an item that overlaps another in time. AMEE Response: #{response.body}")
|
187
|
+
else
|
188
|
+
raise AMEE::UnknownError.new("An error occurred while talking to AMEE: HTTP response code #{response.code}. AMEE Response: #{response.body}")
|
189
|
+
end
|
190
|
+
else
|
191
|
+
raise AMEE::UnknownError.new("An error occurred while talking to AMEE: HTTP response code #{response.code}. AMEE Response: #{response.body}")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def do_request(request, format = @format)
|
196
|
+
# Open HTTP connection
|
197
|
+
@http.start
|
198
|
+
# Do request
|
199
|
+
begin
|
200
|
+
response = send_request(request, format)
|
201
|
+
end while !response_ok?(response)
|
202
|
+
# Return response
|
203
|
+
return response
|
204
|
+
rescue SocketError
|
205
|
+
raise AMEE::ConnectionFailed.new("Connection failed. Check server name or network connection.")
|
206
|
+
ensure
|
207
|
+
# Close HTTP connection
|
208
|
+
@http.finish if @http.started?
|
209
|
+
end
|
210
|
+
|
211
|
+
def send_request(request, format = @format)
|
212
|
+
# Set auth token in cookie (and header just in case someone's stripping cookies)
|
213
|
+
request['Cookie'] = "authToken=#{@auth_token}"
|
214
|
+
request['authToken'] = @auth_token
|
215
|
+
# Set accept header
|
216
|
+
request['Accept'] = content_type(format)
|
217
|
+
# Do the business
|
218
|
+
response = @http.request(request)
|
219
|
+
# Handle 404s
|
220
|
+
if response.code == '404'
|
221
|
+
raise AMEE::NotFound.new("URL doesn't exist on server.")
|
222
|
+
end
|
223
|
+
# Done
|
224
|
+
response
|
225
|
+
end
|
226
|
+
|
227
|
+
public
|
228
|
+
|
229
|
+
def clear_cache
|
230
|
+
if @enable_caching
|
231
|
+
$cache = {}
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|