fireeagle 0.0.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/License.txt +1 -1
- data/Manifest.txt +11 -9
- data/README.txt +38 -10
- data/Rakefile +4 -123
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/lib/fireeagle.rb +32 -42
- data/lib/fireeagle/client.rb +343 -0
- data/lib/fireeagle/location.rb +62 -66
- data/lib/fireeagle/response.rb +31 -0
- data/lib/fireeagle/user.rb +29 -35
- data/lib/fireeagle/version.rb +2 -2
- data/spec/fireeagle_location_spec.rb +60 -0
- data/spec/fireeagle_response_spec.rb +65 -0
- data/spec/fireeagle_spec.rb +150 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +128 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- metadata +91 -58
- data/lib/fireeagle/apibase.rb +0 -6
- data/lib/fireeagle/application.rb +0 -37
- data/lib/fireeagle/base.rb +0 -89
- data/scripts/txt2html +0 -67
- data/test/test_fireeagle.rb +0 -30
- data/test/test_fireeagle_application.rb +0 -46
- data/test/test_fireeagle_location.rb +0 -97
- data/test/test_fireeagle_user.rb +0 -103
- data/test/test_helper.rb +0 -14
data/History.txt
CHANGED
data/License.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
+
config/hoe.rb
|
2
|
+
config/requirements.rb
|
1
3
|
History.txt
|
2
4
|
License.txt
|
3
5
|
Manifest.txt
|
4
6
|
README.txt
|
5
7
|
Rakefile
|
6
8
|
lib/fireeagle.rb
|
7
|
-
lib/fireeagle/
|
8
|
-
lib/fireeagle/apibase.rb
|
9
|
-
lib/fireeagle/base.rb
|
9
|
+
lib/fireeagle/client.rb
|
10
10
|
lib/fireeagle/location.rb
|
11
|
+
lib/fireeagle/response.rb
|
11
12
|
lib/fireeagle/user.rb
|
12
13
|
lib/fireeagle/version.rb
|
13
|
-
scripts/txt2html
|
14
14
|
setup.rb
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
spec/fireeagle_location_spec.rb
|
16
|
+
spec/fireeagle_response_spec.rb
|
17
|
+
spec/fireeagle_spec.rb
|
18
|
+
spec/spec.opts
|
19
|
+
spec/spec_helper.rb
|
20
|
+
tasks/environment.rake
|
21
|
+
tasks/rspec.rake
|
data/README.txt
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
FireEagle[http://fireeagle.
|
1
|
+
FireEagle[http://fireeagle.yahoo.net] (FE) is a system providing centralized
|
2
|
+
management of user location information. FE allows 3rd party developers to
|
3
|
+
pdate and/or access user's location data.
|
4
|
+
|
5
|
+
http://fireeagle.yahoo.net/developer/documentation
|
2
6
|
|
3
7
|
== Installation
|
4
8
|
|
@@ -6,15 +10,39 @@ FireEagle[http://fireeagle.research.yahoo.com/] (FE) is a system providing centr
|
|
6
10
|
|
7
11
|
== Usage
|
8
12
|
|
9
|
-
require 'fireeagle'
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
>> require 'fireeagle'
|
14
|
+
>> client = FireEagle::Client.new(
|
15
|
+
:consumer_key => "<consumer key>",
|
16
|
+
:consumer_secret => "<consumer secret>",
|
17
|
+
:access_token => "[access token]",
|
18
|
+
:access_token_secret => "[access token secret]")
|
19
|
+
|
20
|
+
==== With a User-specific OAuth Access Token
|
21
|
+
|
22
|
+
# update your location
|
23
|
+
>> client.update(:q => "punta del diablo, uruguay") # I wish
|
24
|
+
# query your location
|
25
|
+
>> user = client.user
|
26
|
+
=> #<FireEagle::User:0x1ca5e08 ... >
|
27
|
+
>> user.locations
|
28
|
+
=> [#<FireEagle::Location:0x1cdd9e8 ...>, #<FireEagle::Location:0x1cc8ffc ...>, ... ]
|
29
|
+
>> user.best_guess
|
30
|
+
=> #<FireEagle::Location:0x1cdd9e8 ...>
|
31
|
+
>> user.best_guess.name
|
32
|
+
=> "Punta del Diablo, Uruguay"
|
33
|
+
# lookup a location
|
34
|
+
>> locations = client.lookup(:q => "30022")
|
35
|
+
=> [#<FireEagle::Location:0x1cdd9e8 ...>, #<FireEagle::Location:0x1cc8ffc ...>, ...]
|
36
|
+
>> locations.first.name => "Alpharetta, GA 30022"
|
37
|
+
>> locations.first.place_id => "IrhZMHuYA5s1fFi4Qw"
|
38
|
+
|
39
|
+
== Authorization
|
40
|
+
|
41
|
+
Authorization is handled by OAuth. For more details about the OAuth
|
42
|
+
authorization flow and how it differs based on your application type, please
|
43
|
+
see http://fireeagle.yahoo.net/developer/documentation/authorizing
|
16
44
|
|
17
45
|
Rubyforge Project Page:: http://rubyforge.org/projects/fireeagle
|
18
46
|
Author:: Jesse Newland (http://soylentfoo.jnewland.com) (jnewland@gmail.com[mailto:jnewland@gmail.com])
|
19
|
-
Copyright:: Copyright (c)
|
20
|
-
License::
|
47
|
+
Copyright:: Copyright (c) 2008 Jesse Newland. Portions[http://pastie.caboo.se/private/oevvkdzl0zrdkf8s7hetg] Copyright (c) 2008 Yahoo!
|
48
|
+
License:: Distributed under the same terms as Ruby
|
data/Rakefile
CHANGED
@@ -1,123 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
require 'rake/packagetask'
|
6
|
-
require 'rake/gempackagetask'
|
7
|
-
require 'rake/rdoctask'
|
8
|
-
require 'rake/contrib/rubyforgepublisher'
|
9
|
-
require 'fileutils'
|
10
|
-
require 'hoe'
|
11
|
-
|
12
|
-
include FileUtils
|
13
|
-
require File.join(File.dirname(__FILE__), 'lib', 'fireeagle', 'version')
|
14
|
-
|
15
|
-
AUTHOR = 'Jesse Newland' # can also be an array of Authors
|
16
|
-
EMAIL = "jnewland@gmail.com"
|
17
|
-
DESCRIPTION = "Fire Eagle is a site that keeps track of your current location and helps you share it with other sites and services safely. There are hundreds of potential applications. This gem exposes the FireEagle API as Ruby Classes"
|
18
|
-
GEM_NAME = 'fireeagle' # what ppl will type to install your gem
|
19
|
-
|
20
|
-
@config_file = "~/.rubyforge/user-config.yml"
|
21
|
-
@config = nil
|
22
|
-
def rubyforge_username
|
23
|
-
unless @config
|
24
|
-
begin
|
25
|
-
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
26
|
-
rescue
|
27
|
-
puts <<-EOS
|
28
|
-
ERROR: No rubyforge config file found: #{@config_file}"
|
29
|
-
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
30
|
-
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
31
|
-
EOS
|
32
|
-
exit
|
33
|
-
end
|
34
|
-
end
|
35
|
-
@rubyforge_username ||= @config["username"]
|
36
|
-
end
|
37
|
-
|
38
|
-
RUBYFORGE_PROJECT = 'fireeagle' # The unix name for your project
|
39
|
-
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
40
|
-
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
41
|
-
|
42
|
-
NAME = "fireeagle"
|
43
|
-
REV = nil
|
44
|
-
# UNCOMMENT IF REQUIRED:
|
45
|
-
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
46
|
-
VERS = FireEagle::VERSION::STRING + (REV ? ".#{REV}" : "")
|
47
|
-
CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
|
48
|
-
RDOC_OPTS = ['--quiet', '--title', 'fireeagle documentation',
|
49
|
-
"--opname", "index.html",
|
50
|
-
"--line-numbers",
|
51
|
-
"--main", "README",
|
52
|
-
"--inline-source"]
|
53
|
-
|
54
|
-
class Hoe
|
55
|
-
def extra_deps
|
56
|
-
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Generate all the Rake tasks
|
61
|
-
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
62
|
-
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
63
|
-
p.author = AUTHOR
|
64
|
-
p.description = DESCRIPTION
|
65
|
-
p.email = EMAIL
|
66
|
-
p.summary = DESCRIPTION
|
67
|
-
p.url = HOMEPATH
|
68
|
-
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
69
|
-
p.test_globs = ["test/**/test_*.rb"]
|
70
|
-
p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
|
71
|
-
|
72
|
-
# == Optional
|
73
|
-
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
74
|
-
p.extra_deps = [['hpricot', '>= 0.5.145'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
75
|
-
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
76
|
-
end
|
77
|
-
|
78
|
-
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
|
79
|
-
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
80
|
-
hoe.remote_rdoc_dir = ''
|
81
|
-
|
82
|
-
desc 'Generate website files'
|
83
|
-
task :website_generate do
|
84
|
-
Dir['website/**/*.txt'].each do |txt|
|
85
|
-
sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
desc 'Upload website files to rubyforge'
|
90
|
-
task :website_upload do
|
91
|
-
host = "#{rubyforge_username}@rubyforge.org"
|
92
|
-
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
93
|
-
local_dir = 'website'
|
94
|
-
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
95
|
-
end
|
96
|
-
|
97
|
-
desc 'Generate and upload website files'
|
98
|
-
task :website => [:website_generate, :website_upload, :publish_docs]
|
99
|
-
|
100
|
-
desc 'Release the website and new gem version'
|
101
|
-
task :deploy => [:check_version, :website, :release] do
|
102
|
-
puts "Remember to create SVN tag:"
|
103
|
-
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
104
|
-
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
105
|
-
puts "Suggested comment:"
|
106
|
-
puts "Tagging release #{CHANGES}"
|
107
|
-
end
|
108
|
-
|
109
|
-
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
110
|
-
task :local_deploy => [:website_generate, :install_gem]
|
111
|
-
|
112
|
-
task :check_version do
|
113
|
-
unless ENV['VERSION']
|
114
|
-
puts 'Must pass a VERSION=x.y.z release version'
|
115
|
-
exit
|
116
|
-
end
|
117
|
-
unless ENV['VERSION'] == VERS
|
118
|
-
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
119
|
-
exit
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
|
1
|
+
require 'config/requirements'
|
2
|
+
require 'config/hoe' # setup Hoe + all gem configuration
|
3
|
+
|
4
|
+
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
data/config/hoe.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'fireeagle/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Jesse Newland' # can also be an array of Authors
|
4
|
+
EMAIL = "jnewland@gmail.com"
|
5
|
+
DESCRIPTION = "Ruby wrapper for Yahoo!'s FireEagle"
|
6
|
+
GEM_NAME = 'fireeagle' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'fireeagle' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = FireEagle::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'fireeagle rdoc',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.developer(AUTHOR, EMAIL)
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.summary = DESCRIPTION
|
54
|
+
p.url = HOMEPATH
|
55
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
56
|
+
p.test_globs = ["test/**/test_*.rb"]
|
57
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
58
|
+
|
59
|
+
# == Optional
|
60
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
61
|
+
p.extra_deps = [ ['oauth', '>= 0.2.1'], ['json', '>= 1.1.1'], ['hpricot', '>= 0.6'], ['GeoRuby', '>= 1.3.2'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
62
|
+
|
63
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
68
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
69
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
70
|
+
hoe.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'fireeagle'
|
data/lib/fireeagle.rb
CHANGED
@@ -1,27 +1,41 @@
|
|
1
|
-
|
1
|
+
require 'time'
|
2
|
+
require 'net/https'
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'oauth', ">= 0.2.1"
|
5
|
+
require 'oauth/client/helper'
|
6
|
+
require 'oauth/request_proxy/net_http'
|
7
|
+
require 'json'
|
8
|
+
require 'hpricot'
|
9
|
+
require 'geo_ruby'
|
10
|
+
|
11
|
+
class FireEagle
|
12
|
+
API_SERVER = "https://fireeagle.yahooapis.com"
|
13
|
+
AUTH_SERVER = "https://fireeagle.yahoo.net"
|
14
|
+
REQUEST_TOKEN_PATH = "/oauth/request_token"
|
15
|
+
ACCESS_TOKEN_PATH = "/oauth/access_token"
|
16
|
+
AUTHORIZATION_URL = "#{AUTH_SERVER}/oauth/authorize"
|
17
|
+
MOBILE_AUTH_URL = "#{AUTH_SERVER}/oauth/mobile_auth/"
|
18
|
+
USER_API_PATH = "/api/0.1/user"
|
19
|
+
LOOKUP_API_PATH = "/api/0.1/lookup"
|
20
|
+
UPDATE_API_PATH = "/api/0.1/update"
|
21
|
+
RECENT_API_PATH = "/api/0.1/recent"
|
22
|
+
WITHIN_API_PATH = "/api/0.1/within"
|
23
|
+
FORMAT_JSON = "json"
|
24
|
+
FORMAT_XML = "xml"
|
25
|
+
UPDATE_PARAMS = :lat, :lon, :woeid, :place_id, :address, :mnc, :mcc, :lac, :cid, :postal, :city, :state, :country, :q, :label
|
26
|
+
# not yet supported
|
27
|
+
#,:geom, :upcoming_venue_id, :yahoo_local_id, :plazes_id
|
2
28
|
|
3
|
-
class FireEagle#:nodoc:
|
4
|
-
API_DOMAIN = "fireeagle.research.yahoo.com"
|
5
|
-
API_PATH = "/api/"
|
6
|
-
DEBUG = false
|
7
|
-
|
8
29
|
class Error < RuntimeError #:nodoc:
|
9
30
|
end
|
10
31
|
|
11
32
|
class ArgumentError < Error #:nodoc:
|
12
33
|
end
|
13
|
-
|
34
|
+
|
14
35
|
class FireEagleException < Error #:nodoc:
|
15
36
|
end
|
16
37
|
end
|
17
38
|
|
18
|
-
require 'fireeagle/base'
|
19
|
-
require 'fireeagle/apibase'
|
20
|
-
require 'fireeagle/application'
|
21
|
-
require 'fireeagle/user'
|
22
|
-
require 'fireeagle/location'
|
23
|
-
require 'fireeagle/version'
|
24
|
-
|
25
39
|
#FireEagle additions to the <code>Hash</code> class
|
26
40
|
class Hash
|
27
41
|
#Returns <code>true</code> if the ALL or NONE of the given keys are present in <i>hsh</i>.
|
@@ -33,33 +47,9 @@ class Hash
|
|
33
47
|
end
|
34
48
|
false_count == 0 or false_count == size
|
35
49
|
end
|
36
|
-
|
37
50
|
end
|
38
51
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# def foo
|
44
|
-
# returning values = [] do
|
45
|
-
# values << 'bar'
|
46
|
-
# values << 'baz'
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# foo # => ['bar', 'baz']
|
51
|
-
#
|
52
|
-
# def foo
|
53
|
-
# returning [] do |values|
|
54
|
-
# values << 'bar'
|
55
|
-
# values << 'baz'
|
56
|
-
# end
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# foo # => ['bar', 'baz']
|
60
|
-
#
|
61
|
-
def returning(value)
|
62
|
-
yield(value)
|
63
|
-
value
|
64
|
-
end
|
65
|
-
end
|
52
|
+
require File.dirname(__FILE__) + '/fireeagle/client'
|
53
|
+
require File.dirname(__FILE__) + '/fireeagle/location'
|
54
|
+
require File.dirname(__FILE__) + '/fireeagle/user'
|
55
|
+
require File.dirname(__FILE__) + '/fireeagle/response'
|
@@ -0,0 +1,343 @@
|
|
1
|
+
class FireEagle
|
2
|
+
class Client
|
3
|
+
attr_reader :access_token, :request_token, :consumer, :format
|
4
|
+
|
5
|
+
# Initialize a FireEagle Client. Takes an options Hash.
|
6
|
+
#
|
7
|
+
# == Required keys:
|
8
|
+
#
|
9
|
+
# [<tt>:consumer_key</tt>] OAuth Consumer key representing your FireEagle Application
|
10
|
+
# [<tt>:consumer_secret</tt>] OAuth Consumer secret representing your FireEagle Application
|
11
|
+
#
|
12
|
+
# == Optional keys:
|
13
|
+
#
|
14
|
+
# [<tt>:request_token</tt>] OAuth Request Token, for use with convert_to_access_token
|
15
|
+
# [<tt>:request_token_secret</tt>] OAuth Request Token Secret, for use with convert_to_access_token
|
16
|
+
# [<tt>:access_token</tt>] OAuth Token, either User-specific or General-purpose
|
17
|
+
# [<tt>:access_token_secret</tt>] OAuth Token, either User-specific or General-purpose
|
18
|
+
# [<tt>:app_id</tt>] Your Mobile Application ID
|
19
|
+
# [<tt>:debug</tt>] Boolean
|
20
|
+
#
|
21
|
+
# User-specific OAuth tokens tie FireEagle users to your application. As such, they are intended to be
|
22
|
+
# distributed (with keys) to that user's mobile device and/or computer running your desktop or mobile client.
|
23
|
+
# For web-based applications User-specific tokens will be retrieved by your web server where they should be
|
24
|
+
# treated as private data. Take care to avoid releasing this data to the public, as the corresponding User's location
|
25
|
+
# information may be inadvertently exposed. User-specific OAuth tokens should be considered the property of
|
26
|
+
# your users.
|
27
|
+
#
|
28
|
+
# General-purpose OAuth tokens are tied to your application and allow you, as a developer, to make more
|
29
|
+
# general (often batch-style) queries against FireEagle. As a result, allowing this token/secret combination
|
30
|
+
# loose has the potential to reveal a much greater amount of personal data. In an attempt to mitigate this, we will
|
31
|
+
# only grant general-purpose tokens to web applications (contact us with details, if you seek an exception). In
|
32
|
+
# addition, we require developers to provide a restrictive IP range at registration time in order to further mitigate
|
33
|
+
# the risk of general-purpose tokens being used inappropriately.
|
34
|
+
#
|
35
|
+
# In general, OAuth tokens should be considered sacrosanct in order to help us respect our users' privacy. Please
|
36
|
+
# take this responsibility on as your own. If your Application Oauth tokens are compromised, FireEagle will
|
37
|
+
# turn off your application service until the problem is resolved.
|
38
|
+
#
|
39
|
+
# If the Client is initialized without an OAuth access token, it's assumed you're operating a non-web based application.
|
40
|
+
#
|
41
|
+
# == Non web-based applications
|
42
|
+
#
|
43
|
+
# For non web-based applications, such as a mobile client application, the authentication between the user and
|
44
|
+
# the application is slightly different. The request token is displayed to the user by the client application. The
|
45
|
+
# user then logs into the FireEagle website (using mobile_authorization_url) and enters this code to authorize the application.
|
46
|
+
# When the user finishes the authorization step the client application exchanges the request token for an access token
|
47
|
+
# (using convert_to_access_token). This is a lightweight method for non-web application users to authenticate an application
|
48
|
+
# without entering any identifying information into a potentially insecure application. Request tokens are valid for only
|
49
|
+
# 1 hour after being issued.
|
50
|
+
#
|
51
|
+
# == Example mobile-based authentication flow:
|
52
|
+
#
|
53
|
+
# Initialize a client with your consumer key, consumer secret, and your mobile application id:
|
54
|
+
#
|
55
|
+
# >> c = FireEagle::Client.new(:consumer_key => "key", :consumer_secret => "sekret", :app_id => 12345)
|
56
|
+
# => #<FireEagle::Client:0x1ce2e70 ... >
|
57
|
+
#
|
58
|
+
# Generate a request token:
|
59
|
+
#
|
60
|
+
# >> c.get_request_token
|
61
|
+
# => #<OAuth::Token:0x1cdb5bc @token="ENTER_THIS_TOKEN", @secret="sekret">
|
62
|
+
#
|
63
|
+
# Prompt your user to visit your app's mobile authorization url and enter ENTER_THIS_TOKEN:
|
64
|
+
#
|
65
|
+
# >> c.mobile_authorization_url
|
66
|
+
# => "http://fireeagle.yahoo.net/oauth/mobile_auth/12345"
|
67
|
+
#
|
68
|
+
# Once the user has indicated to you that they've done this, convert their request token to an access token:
|
69
|
+
#
|
70
|
+
# >> c.convert_to_access_token
|
71
|
+
# => #<OAuth::Token:0x1cd3bf0 @token="access_token", @secret="access_token_secret">
|
72
|
+
#
|
73
|
+
# You're done!
|
74
|
+
def initialize(options = {})
|
75
|
+
options = {
|
76
|
+
:debug => false,
|
77
|
+
:format => FireEagle::FORMAT_XML
|
78
|
+
}.merge(options)
|
79
|
+
|
80
|
+
# symbolize keys
|
81
|
+
options.map do |k,v|
|
82
|
+
options[k.to_sym] = v
|
83
|
+
end
|
84
|
+
raise FireEagle::ArgumentError, "OAuth Consumer Key and Secret required" if options[:consumer_key].nil? || options[:consumer_secret].nil?
|
85
|
+
@consumer = OAuth::Consumer.new(options[:consumer_key], options[:consumer_secret])
|
86
|
+
@debug = options[:debug]
|
87
|
+
@format = options[:format]
|
88
|
+
@app_id = options[:app_id]
|
89
|
+
if options[:access_token] && options[:access_token_secret]
|
90
|
+
@access_token = OAuth::Token.new(options[:access_token], options[:access_token_secret])
|
91
|
+
else
|
92
|
+
@access_token = nil
|
93
|
+
end
|
94
|
+
if options[:request_token] && options[:request_token_secret]
|
95
|
+
@request_token = OAuth::Token.new(options[:request_token], options[:request_token_secret])
|
96
|
+
else
|
97
|
+
@request_token = nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Obtain an <strong>new</strong> unauthorized OAuth Request token
|
102
|
+
def get_request_token(force_token_regeneration = false)
|
103
|
+
if force_token_regeneration || @request_token.nil?
|
104
|
+
response = get(FireEagle::REQUEST_TOKEN_PATH, :token => nil)
|
105
|
+
@request_token = create_token(response)
|
106
|
+
end
|
107
|
+
@request_token
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return the Fire Eagle authorization URL for your mobile application. At this URL, the User will be prompted for their request_token.
|
111
|
+
def mobile_authorization_url
|
112
|
+
raise FireEagle::ArgumentError, ":app_id required" if @app_id.nil?
|
113
|
+
"#{FireEagle::MOBILE_AUTH_URL}#{@app_id}"
|
114
|
+
end
|
115
|
+
|
116
|
+
# The URL the user must access to authorize this token. request_token must be called first. For use by web-based and desktop-based applications.
|
117
|
+
def authorization_url
|
118
|
+
raise FireEagle::ArgumentError, "call #get_request_token first" if @request_token.nil?
|
119
|
+
"#{FireEagle::AUTHORIZATION_URL}?oauth_token=#{@request_token.token}"
|
120
|
+
end
|
121
|
+
|
122
|
+
#Exchange an authorized OAuth Request token for an access token. For use by desktop-based and mobile applications.
|
123
|
+
def convert_to_access_token
|
124
|
+
raise FireEagle::ArgumentError, "call #get_request_token and have user authorize the token first" if @request_token.nil?
|
125
|
+
response = get(FireEagle::ACCESS_TOKEN_PATH, :token => @request_token)
|
126
|
+
@access_token = create_token(response)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Disambiguates potential values for update query. Results from lookup can be passed to
|
130
|
+
# update to ensure that FireEagle will understand how to parse the Location Hash.
|
131
|
+
#
|
132
|
+
# All three Location methods (lookup, update, and within) accept a Location Hash.
|
133
|
+
#
|
134
|
+
# There is a specific order for looking up locations. For example, if you provide lat, lon, and address,
|
135
|
+
# FireEagle will use the the latitude and longitude geo-coordinates and ignore the address.
|
136
|
+
#
|
137
|
+
# Location Hash keys, in order of priority:
|
138
|
+
#
|
139
|
+
# [<tt>(:lat, :lon)</tt>] both required, valid values are floats of -180 to 180 for lat and -90 to 90 for lon
|
140
|
+
# [<tt>(:woeid)</tt>] Where on Earth ID
|
141
|
+
# [<tt>:place_id</tt>] Place ID (via Flickr/Upcomoing); deprecated in favor of WOE IDs when possible
|
142
|
+
# [<tt>:address</tt>] street address (may contain a full address, but will be combined with postal, city, state, and country when available)
|
143
|
+
# [<tt>(:mnc, :mcc, :lac, :cid)</tt>] cell tower information, all required (as integers) for a valid tower location
|
144
|
+
# [<tt>:postal</tt>] a ZIP or postal code (combined with address, city, state, and country when available)
|
145
|
+
# [<tt>:city</tt>] city (combined with address, postal, state, and country when available)
|
146
|
+
# [<tt>:state</tt>] state (combined with address, postal, city, and country when available)
|
147
|
+
# [<tt>:country</tt>] country (combined with address, postal, city, and state when available)
|
148
|
+
# [<tt>:q</tt>] Free-text fallback containing user input. Lat/lon pairs and geometries will be extracted if possible, otherwise this string will be geocoded as-is.
|
149
|
+
#
|
150
|
+
# Not yet supported:
|
151
|
+
#
|
152
|
+
# * <tt>upcoming_venue_id</tt>
|
153
|
+
# * <tt>yahoo_local_id</tt>
|
154
|
+
# * <tt>plazes_id</tt>
|
155
|
+
def lookup(params)
|
156
|
+
raise FireEagle::ArgumentError, "OAuth Access Token Required" unless @access_token
|
157
|
+
|
158
|
+
response = get(FireEagle::LOOKUP_API_PATH + ".#{format}", :params => params)
|
159
|
+
|
160
|
+
if json?
|
161
|
+
JSON.parse(response.body)
|
162
|
+
else
|
163
|
+
FireEagle::Response.new(response.body).locations
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Sets a User's current Location using using a Place ID hash or a set of Location parameters. If the User
|
168
|
+
# provides a Location unconfirmed with lookup then FireEagle makes a best guess as to the User's Location.
|
169
|
+
#
|
170
|
+
# All three Location methods (lookup, update, and within) accept a Location Hash.
|
171
|
+
#
|
172
|
+
# There is a specific order for looking up locations. For example, if you provide lat, lon, and address,
|
173
|
+
# FireEagle will use the the latitude and longitude geo-coordinates and ignore the address.
|
174
|
+
#
|
175
|
+
# Location Hash keys, in order of priority:
|
176
|
+
#
|
177
|
+
# [<tt>(:lat, :lon)</tt>] both required, valid values are floats of -180 to 180 for lat and -90 to 90 for lon
|
178
|
+
# [<tt>:place_id</tt>] Place ID - valid values decrypts to an integer value
|
179
|
+
# [<tt>:address</tt>] street address (may contain a full address, but will be combined with postal, city, state, and country when available)
|
180
|
+
# [<tt>(:mnc, :mcc, :lac, :cid)</tt>] cell tower information, all required (as integers) for a valid tower location
|
181
|
+
# [<tt>:postal</tt>] a ZIP or postal code (combined with address, city, state, and country when available)
|
182
|
+
# [<tt>:city</tt>] city (combined with address, postal, state, and country when available)
|
183
|
+
# [<tt>:state</tt>] state (combined with address, postal, city, and country when available)
|
184
|
+
# [<tt>:country</tt>] country (combined with address, postal, city, and state when available)
|
185
|
+
# [<tt>:q</tt>] Free-text fallback containing user input. Lat/lon pairs and geometries will be extracted if possible, otherwise this string will be geocoded as-is.
|
186
|
+
#
|
187
|
+
# Not yet supported:
|
188
|
+
#
|
189
|
+
# * <tt>upcoming_venue_id</tt>
|
190
|
+
# * <tt>yahoo_local_id</tt>
|
191
|
+
# * <tt>plazes_id</tt>
|
192
|
+
def update(location = {})
|
193
|
+
raise FireEagle::ArgumentError, "OAuth Access Token Required" unless @access_token
|
194
|
+
|
195
|
+
location = sanitize_location_hash(location)
|
196
|
+
|
197
|
+
response = post(FireEagle::UPDATE_API_PATH + ".#{format}", :params => location)
|
198
|
+
|
199
|
+
if json?
|
200
|
+
JSON.parse(response.body)
|
201
|
+
else
|
202
|
+
FireEagle::Response.new(response.body)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns the Location of a User.
|
207
|
+
def user
|
208
|
+
raise FireEagle::ArgumentError, "OAuth Access Token Required" unless @access_token
|
209
|
+
|
210
|
+
response = get(FireEagle::USER_API_PATH + ".#{format}")
|
211
|
+
|
212
|
+
if json?
|
213
|
+
JSON.parse(response.body)
|
214
|
+
else
|
215
|
+
FireEagle::Response.new(response.body).users.first
|
216
|
+
end
|
217
|
+
end
|
218
|
+
alias_method :location, :user
|
219
|
+
|
220
|
+
# <b>NOTE: not implemented yet</b>
|
221
|
+
#
|
222
|
+
# Query for Users of an Application who have updated their Location recently. Returns a list of
|
223
|
+
# Users for the Application with recently updated locations.
|
224
|
+
def recent(count = 10, start = 0)
|
225
|
+
raise FireEagle::ArgumentError, "OAuth Access Token Required" unless @access_token
|
226
|
+
|
227
|
+
params = { :count => count, :start => start }
|
228
|
+
|
229
|
+
response = get(FireEagle::RECENT_API_PATH + ".#{format}", :params => params)
|
230
|
+
|
231
|
+
if json?
|
232
|
+
JSON.parse(response.body)
|
233
|
+
else
|
234
|
+
FireEagle::Response.new(response.body).users
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# <b>NOTE: not implemented yet</b>
|
239
|
+
# Takes a Place ID or a Location and returns a list of users of your application who are within the bounding box of that Location.
|
240
|
+
#
|
241
|
+
# Location Hash keys, in order of priority:
|
242
|
+
#
|
243
|
+
# [<tt>(:lat, :lon)</tt>] both required, valid values are floats of -180 to 180 for lat and -90 to 90 for lon
|
244
|
+
# [<tt>:woeid</tt>] Where on Earth ID
|
245
|
+
# [<tt>:place_id</tt>] Place ID
|
246
|
+
# [<tt>:address</tt>] street address (may contain a full address, but will be combined with postal, city, state, and country when available)
|
247
|
+
# [<tt>(:mnc, :mcc, :lac, :cid)</tt>] cell tower information, all required (as integers) for a valid tower location
|
248
|
+
# [<tt>:postal</tt>] a ZIP or postal code (combined with address, city, state, and country when available)
|
249
|
+
# [<tt>:city</tt>] city (combined with address, postal, state, and country when available)
|
250
|
+
# [<tt>:state</tt>] state (combined with address, postal, city, and country when available)
|
251
|
+
# [<tt>:country</tt>] country (combined with address, postal, city, and state when available)
|
252
|
+
# [<tt>:q</tt>] Free-text fallback containing user input. Lat/lon pairs and geometries will be extracted if possible, otherwise this string will be geocoded as-is.
|
253
|
+
#
|
254
|
+
# Not yet supported:
|
255
|
+
#
|
256
|
+
# * <tt>upcoming_venue_id</tt>
|
257
|
+
# * <tt>yahoo_local_id</tt>
|
258
|
+
# * <tt>plazes_id</tt>
|
259
|
+
def within(location = {}, count = 10, start = 0)
|
260
|
+
raise FireEagle::ArgumentError, "OAuth Access Token Required" unless @access_token
|
261
|
+
|
262
|
+
location = sanitize_location_hash(location)
|
263
|
+
params = { :count => count, :start => start }.merge(location)
|
264
|
+
|
265
|
+
response = get(FireEagle::WITHIN_API_PATH + ".#{format}", :params => params)
|
266
|
+
|
267
|
+
if json?
|
268
|
+
JSON.parse(response.body)
|
269
|
+
else
|
270
|
+
FireEagle::Response.new(response.body).users
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
protected
|
275
|
+
|
276
|
+
def sanitize_location_hash(location)
|
277
|
+
location.map do |k,v|
|
278
|
+
location[k.to_sym] = v
|
279
|
+
end
|
280
|
+
|
281
|
+
location = location.reject { |key, value| !FireEagle::UPDATE_PARAMS.include?(key) }
|
282
|
+
raise FireEagle::ArgumentError, "Requires all or none of :lat, :lon" unless location.has_all_or_none_keys?(:lat, :lon)
|
283
|
+
raise FireEagle::ArgumentError, "Requires all or none of :mnc, :mcc, :lac, :cellid" unless location.has_all_or_none_keys?(:mnc, :mcc, :lac, :cid)
|
284
|
+
location
|
285
|
+
end
|
286
|
+
|
287
|
+
def xml? #:nodoc:
|
288
|
+
format == FireEagle::FORMAT_XML
|
289
|
+
end
|
290
|
+
|
291
|
+
def json? #:nodoc:
|
292
|
+
format == FireEagle::FORMAT_JSON
|
293
|
+
end
|
294
|
+
|
295
|
+
def create_token(response) #:nodoc:
|
296
|
+
token = Hash[*response.body.split("&").map { |x| x.split("=") }.flatten]
|
297
|
+
OAuth::Token.new(token["oauth_token"], token["oauth_token_secret"])
|
298
|
+
end
|
299
|
+
|
300
|
+
# Is the Client in debug mode?
|
301
|
+
def debug?
|
302
|
+
@debug == true
|
303
|
+
end
|
304
|
+
|
305
|
+
def get(url, options = {}) #:nodoc:
|
306
|
+
request(:get, url, options)
|
307
|
+
end
|
308
|
+
|
309
|
+
def post(url, options = {}) #:nodoc:
|
310
|
+
request(:post, url, options)
|
311
|
+
end
|
312
|
+
|
313
|
+
def request(method, url, options) #:nodoc:
|
314
|
+
options = {
|
315
|
+
:params => {},
|
316
|
+
:token => @access_token
|
317
|
+
}.merge(options)
|
318
|
+
|
319
|
+
request_uri = URI.parse(FireEagle::API_SERVER + url)
|
320
|
+
http = Net::HTTP.new(request_uri.host, request_uri.port)
|
321
|
+
http.set_debug_output $stderr if debug?
|
322
|
+
if FireEagle::API_SERVER =~ /https:/
|
323
|
+
http.use_ssl = true
|
324
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
325
|
+
end
|
326
|
+
|
327
|
+
request = nil
|
328
|
+
if method == :post
|
329
|
+
request = Net::HTTP::Post.new(request_uri.path)
|
330
|
+
request.set_form_data(options[:params])
|
331
|
+
elsif method == :get
|
332
|
+
qs = options[:params].collect { |k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
|
333
|
+
request = Net::HTTP::Get.new(request_uri.path + "?" + qs)
|
334
|
+
end
|
335
|
+
request.oauth!(http, consumer, options[:token])
|
336
|
+
response = http.request(request)
|
337
|
+
raise FireEagle::FireEagleException, "Internal Server Error" if response.code == '500'
|
338
|
+
raise FireEagle::FireEagleException, "Method Not Implemented Yet" if response.code == '400'
|
339
|
+
response
|
340
|
+
end
|
341
|
+
|
342
|
+
end
|
343
|
+
end
|