mapsqueak 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/squeak.rb +105 -0
- data/lib/mapsqueak.rb +246 -0
- metadata +57 -0
data/bin/squeak.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# squeak.rb - update mapsqueak.heroku.com with a lat/long and a message (a squeak)
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.dirname($PROGRAM_NAME)
|
6
|
+
$LOAD_PATH.unshift File.dirname($PROGRAM_NAME) + "/../lib"
|
7
|
+
|
8
|
+
require 'opt_simple'
|
9
|
+
require 'mapsqueak'
|
10
|
+
|
11
|
+
defaults = {
|
12
|
+
:host => 'http://mapsqueak.heroku.com' # http://localhost:3000
|
13
|
+
}
|
14
|
+
|
15
|
+
opts = OptSimple.new(defaults).parse_opts! do
|
16
|
+
argument "--latitude", "Latitude in decimal degrees","LAT"
|
17
|
+
argument "--longitude", "Longitude in decimal degrees","LONG"
|
18
|
+
argument %w[-t --text], "Squeak text", "TEXT"
|
19
|
+
argument %w[-d --duration], "Duration in hours","DURATION" do | arg |
|
20
|
+
dur = arg.to_f
|
21
|
+
if dur > 0.0 and dur <= 24.0
|
22
|
+
set_opt dur
|
23
|
+
else
|
24
|
+
error "Duration must be between 0 and 24 hours"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
option "--host", "MapSqueak host","URL"
|
28
|
+
option %w[--access-token], "Facebook access token to post mapsqueak","TOKEN"
|
29
|
+
flag %w[--facebook-test-user], "Create a Facebook test user using Mapsqueak's app token"
|
30
|
+
end
|
31
|
+
puts opts
|
32
|
+
|
33
|
+
|
34
|
+
# TODO: add signin capability
|
35
|
+
# TODO: re-add the facebook functionality
|
36
|
+
m = MapSqueakSession.new
|
37
|
+
|
38
|
+
m.post_squeak({
|
39
|
+
:latitude => opts.latitude.dup.gsub("\\",''),
|
40
|
+
:longitude =>opts.longitude.dup.gsub("\\",''),
|
41
|
+
:text =>opts.text.dup,
|
42
|
+
:duration => opts.duration
|
43
|
+
})
|
44
|
+
|
45
|
+
__END__
|
46
|
+
|
47
|
+
|
48
|
+
puts "Auto confirming squeak ..."
|
49
|
+
|
50
|
+
update = {:squeak => Hash.new}
|
51
|
+
update[:squeak][:latitude] = initial_return_hash['squeak']['latitude']
|
52
|
+
update[:squeak][:longitude] = initial_return_hash['squeak']['longitude']
|
53
|
+
|
54
|
+
# PUT /squeaks/:id(.:format) {:action=>"update", :controller=>"squeaks"}
|
55
|
+
confirmation_curl_str = "curl -v --request PUT --data #{update.to_json} #{opts.host}/squeaks/#{initial_return_hash['squeak']['id']}.json -H \"Content-Type: application/json\" 2>> ruby_err.html"
|
56
|
+
|
57
|
+
puts confirmation_curl_str
|
58
|
+
|
59
|
+
confirmation_return = `#{confirmation_curl_str}`
|
60
|
+
puts "Confirmed."
|
61
|
+
confirmation_return_hash = JSON.parse(confirmation_return)
|
62
|
+
# Mapsqueak is all set, now update facebook if desired
|
63
|
+
user = nil
|
64
|
+
login_url = nil
|
65
|
+
if opts.include?('access-token')
|
66
|
+
user = Koala::Facebook::API.new(opts.access_token)
|
67
|
+
elsif(opts.include?('facebook-test-user'))
|
68
|
+
test_users = Koala::Facebook::TestUsers.new(:app_id => '107582139349630', :secret => "ca16bbd5834ab7d4b012ec5e84a0d003")
|
69
|
+
user_info = test_users.create(true, "offline_access,read_stream,manage_pages,publish_stream")
|
70
|
+
login_url = user_info['login_url']
|
71
|
+
user = Koala::Facebook::API.new(user_info['access_token'])
|
72
|
+
end
|
73
|
+
|
74
|
+
unless user.nil?
|
75
|
+
puts "Using the following facebook user: #{user.inspect}"
|
76
|
+
|
77
|
+
picture_url = "http://maps.googleapis.com/maps/api/staticmap?center=#{update[:latitude]},#{update[:longitude]}&zoom=13&size=200x200&maptype=roadmap&markers=color:blue%7Clabel:M%7C#{update[:latitude]},#{update[:longitude]}&sensor=true"
|
78
|
+
|
79
|
+
puts "Google image url: #{picture_url}"
|
80
|
+
|
81
|
+
# Use google's static map api to get an image for the squeak
|
82
|
+
id = user.put_wall_post("MapSqueak update at #{Time.now.strftime('')}",{:name => 'squeak name',
|
83
|
+
:link => "#{opts.host}/squeaks/#{confirmation_return_hash['squeak']['id']}",
|
84
|
+
:caption => opts.text,
|
85
|
+
:description => "the description of the squeak, TBD",
|
86
|
+
:picture => picture_url})
|
87
|
+
puts "Updated facebook with id: #{id}"
|
88
|
+
puts "Visit #{login_url} to see it ..." unless login_url.nil?
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
__END__
|
93
|
+
|
94
|
+
# To update the squeak using POST params, similar to the web client
|
95
|
+
#curl_str = "curl -v -F squeak[latitude]=#{opts.latitude} -F squeak[longitude]=#{opts.longitude} -F squeak[text]=\'#{opts.text}\' -F duration=#{opts.duration} #{opts.host}/squeaks/ 2> ruby_err.html"
|
96
|
+
# TODO: make this work.
|
97
|
+
class MapSqueak
|
98
|
+
include HTTParty
|
99
|
+
format :json
|
100
|
+
def self.squeak(host,params)
|
101
|
+
post("#{host}/squeaks/",:body=>params)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
$stderr.puts params.to_json
|
105
|
+
MapSqueak.squeak(opts.host,params.to_json)
|
data/lib/mapsqueak.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
= mapsqueak - a reference implementation for MapSqueak clients
|
4
|
+
|
5
|
+
=end
|
6
|
+
|
7
|
+
require 'json'
|
8
|
+
require 'koala'
|
9
|
+
require 'rexml/document'
|
10
|
+
include REXML
|
11
|
+
|
12
|
+
module XmlHelpers
|
13
|
+
def xml_element(tag,text=nil)
|
14
|
+
e = Element.new(tag)
|
15
|
+
e << Text.new(text) unless text.nil?
|
16
|
+
e
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# MapSqueakSession - an class that encapsulates a session with the mapsqueak server.
|
21
|
+
#
|
22
|
+
class MapSqueakSession
|
23
|
+
include XmlHelpers
|
24
|
+
attr_accessor :host, :facebook_token
|
25
|
+
attr_reader :session_cookie
|
26
|
+
|
27
|
+
def initialize(host = 'http://mapsqueak.heroku.com', username=nil,password=nil)
|
28
|
+
@host = host
|
29
|
+
@cookie_file = 'anonymous@anaonymous.com.cookies'
|
30
|
+
end
|
31
|
+
|
32
|
+
# sign in by email/password.
|
33
|
+
# note that a remember_token will be saved in a cookie file
|
34
|
+
def sign_in(email,password)
|
35
|
+
signin_xml = Document.new
|
36
|
+
signin_xml.add_element('session')
|
37
|
+
signin_xml.root << xml_element('email',email)
|
38
|
+
signin_xml.root << xml_element('password',password)
|
39
|
+
puts signin_xml.to_s
|
40
|
+
|
41
|
+
@cookie_file = "#{email}.cookies"
|
42
|
+
|
43
|
+
curl_str = "curl --data \'#{signin_xml.to_s}\' #{self.host}/sessions.xml -H \"Content-Type: application/xml\" --cookie-jar #{@cookie_file}"
|
44
|
+
|
45
|
+
result = `#{curl_str}`
|
46
|
+
puts result
|
47
|
+
doc = Document.new(result)
|
48
|
+
@user_id = XPath.first(doc,"hash/user-id").text
|
49
|
+
end
|
50
|
+
|
51
|
+
# sign the current user out.
|
52
|
+
# note that the cookie file will be deleted.
|
53
|
+
def sign_out
|
54
|
+
curl_str = "curl #{self.host}/sessions --request DELETE --cookie #{@cookie_file}"
|
55
|
+
puts curl_str
|
56
|
+
`#{curl_str}`
|
57
|
+
File.unlink(@cookie_file)
|
58
|
+
end
|
59
|
+
|
60
|
+
# post a new squeak. the squeak can either be whatever the ClientSqueak constructor accepts -
|
61
|
+
# a String of json or xml, or a hash, or it can be a ClientSqueak object. Talk about flexibility!
|
62
|
+
# the send_format must be :xml or :json
|
63
|
+
def post_squeak(squeak,send_format = :xml)
|
64
|
+
s = nil
|
65
|
+
case squeak
|
66
|
+
when ClientSqueak
|
67
|
+
s = squeak
|
68
|
+
when Hash
|
69
|
+
s = ClientSqueak.new(squeak)
|
70
|
+
end
|
71
|
+
unless [:json, :xml].include?(send_format)
|
72
|
+
$stderr.puts "Error: send_format must be in json or xml"
|
73
|
+
end
|
74
|
+
format_str = send_format.to_s
|
75
|
+
data = s.send("to_#{format_str}")
|
76
|
+
curl_str = "curl --data \'#{data}\' #{self.host}/squeaks.#{format_str} -H \"Content-Type: application/#{format_str}\" --cookie #{@cookie_file}"
|
77
|
+
|
78
|
+
# execute the curl command
|
79
|
+
`#{curl_str}`
|
80
|
+
end
|
81
|
+
|
82
|
+
# get a list of no more than max squeaks closest to the given center_latitude/centerlongitude
|
83
|
+
# The format must either be :json or :xml.
|
84
|
+
# TODO: create a list of ClientSqueak objects, or make a get_squeak_objects function
|
85
|
+
def get_squeaks(center_latitude,center_longitude,max = 100,format=:json)
|
86
|
+
# curl "http://192.168.0.2:3000/squeaks.xml?num_squeaks=3¢er_latitude=50.0¢er_longitude=-1.8"
|
87
|
+
unless [:json, :xml].include?(format)
|
88
|
+
$stderr.puts "Error: must be in json or xml"
|
89
|
+
end
|
90
|
+
|
91
|
+
squeaks = `curl #{self.host}/squeaks.#{format.to_s}?num_squeaks=#{max}¢er_latitude=#{center_latitude}¢er_longitude=#{center_longitude}`
|
92
|
+
|
93
|
+
# TODO: parse these appropriately
|
94
|
+
end
|
95
|
+
|
96
|
+
# return all of my squeaks in a specified format, either :xml or :json
|
97
|
+
def get_my_squeaks(format=:json)
|
98
|
+
unless [:json, :xml].include?(format)
|
99
|
+
$stderr.puts "Error: must be in json or xml"
|
100
|
+
end
|
101
|
+
# TODO: add a hash based on the parameters requested and use session token
|
102
|
+
# T
|
103
|
+
`curl #{self.host}/users/#{@user_id}.#{format.to_s} --cookie #{@cookie_file}`
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# ClientSqueak - a class that encapsulates a client side squeak
|
108
|
+
# Note that if I am not the owner of a squeak, I will not know the user
|
109
|
+
class ClientSqueak
|
110
|
+
include XmlHelpers
|
111
|
+
attr_accessor :latitude, :longitude, :text, :duration, :expires, :username
|
112
|
+
|
113
|
+
@@mandatory_parameters = %w[latitude longitude text duration]
|
114
|
+
@@min_latitude = -90.0
|
115
|
+
@@max_latitude = 90.0
|
116
|
+
@@min_longitude = -180.0
|
117
|
+
@@max_longitude = 180.0
|
118
|
+
@@min_duration = 0.0
|
119
|
+
@@max_duration = 24.0
|
120
|
+
@@max_text_length = 140
|
121
|
+
|
122
|
+
# Initialize a new squeak which must be in an allowable format:
|
123
|
+
# json - a String representation of a JSON object
|
124
|
+
# e.g. {\"squeak\":{\"latitude\":\"54.1\",\"longitude\":\"-1.7\",\"duration\":\"2\",\"text\":\"Another squeak!\"}}
|
125
|
+
# xml - a String representation of an XML blob
|
126
|
+
# e.g. <squeak><latitude>54.1</latitude><longitude>-1.7</longitude><text>Another squeak!</text><duration>2</duration></squeak>
|
127
|
+
# hash - a hash representation of a squeak
|
128
|
+
# e.g. {:squeak => {:latitude=> 54.1, :longitude=>-1.69, :text => "Another squeak!", :duration => 2}}
|
129
|
+
# OR if you are lazy (like me) you can just specify the inner hash:
|
130
|
+
# e.g. {:latitude=> 54.1, :longitude=>-1.69, :text => "Another squeak!", :duration => 2}
|
131
|
+
def initialize(squeak)
|
132
|
+
@original_squeak = squeak
|
133
|
+
temp_hash = {:squeak => {}}
|
134
|
+
case squeak
|
135
|
+
when Hash
|
136
|
+
# just to be nice, we won't force the user to specify the outer wrapping
|
137
|
+
if squeak.has_key? 'squeak'
|
138
|
+
temp_hash = squeak.dup
|
139
|
+
else
|
140
|
+
temp_hash = {:squeak => squeak}
|
141
|
+
end
|
142
|
+
|
143
|
+
when String
|
144
|
+
begin
|
145
|
+
temp_hash = JSON.parse(squeak)
|
146
|
+
rescue Exception => e
|
147
|
+
begin
|
148
|
+
doc = Document.new(squeak)
|
149
|
+
# a nice flexible way to parse the XML. as long as the XML
|
150
|
+
# is only one level deep
|
151
|
+
doc.elements.each('squeak/') do | el |
|
152
|
+
el.each do |child|
|
153
|
+
temp_hash[:squeak][child.name.to_sym] = child.text
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rescue Exception => e2
|
157
|
+
raise "Can't parse squeak text: #{squeak}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
t = temp_hash['squeak'] || temp_hash[:squeak]
|
163
|
+
parms_set = []
|
164
|
+
t.keys.each do | k |
|
165
|
+
# this will set and validate the parameters
|
166
|
+
self.send("#{k.to_s}=",t[k])
|
167
|
+
parms_set << k.to_s
|
168
|
+
end
|
169
|
+
|
170
|
+
# but we need to make sure that all of the mandatory parameters are defined
|
171
|
+
unless (@@mandatory_parameters - parms_set).empty?
|
172
|
+
raise "Must have duration, lat and long and text"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# convert the squeak to XML format
|
177
|
+
# e.g. <squeak><latitude>54.1</latitude><longitude>-1.7</longitude><text>Another squeak!</text><duration>2</duration></squeak>
|
178
|
+
def to_xml
|
179
|
+
params_xml = Document.new
|
180
|
+
params_xml.add_element('squeak')
|
181
|
+
params_xml.root << xml_element('latitude',self.latitude.to_s)
|
182
|
+
params_xml.root << xml_element('longitude',self.longitude.to_s)
|
183
|
+
params_xml.root << xml_element('text',self.text)
|
184
|
+
params_xml.root << xml_element('duration',self.duration.to_s)
|
185
|
+
params_xml
|
186
|
+
end
|
187
|
+
|
188
|
+
# convert the squeak to JSON format
|
189
|
+
# e.g. {\"squeak\":{\"latitude\":\"54.1\",\"longitude\":\"-1.7\",\"duration\":\"2\",\"text\":\"Another squeak!\"}}
|
190
|
+
def to_json
|
191
|
+
self.to_hash.to_json
|
192
|
+
end
|
193
|
+
|
194
|
+
# convert the squeak to a Hash
|
195
|
+
def to_hash
|
196
|
+
{
|
197
|
+
:squeak=> {
|
198
|
+
:latitude => self.latitude.to_s,
|
199
|
+
:longitude => self.longitude.to_s,
|
200
|
+
:duration => self.duration.to_s,
|
201
|
+
:text => self.text
|
202
|
+
}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# set the latitude for the squeak
|
207
|
+
# must be between @@min_latitude and @@max_latitude
|
208
|
+
def latitude=(latitude)
|
209
|
+
lat = latitude.to_f
|
210
|
+
raise "Bad latitude" if lat < @@min_latitude
|
211
|
+
raise "Bad latitude" if lat > @@max_latitude
|
212
|
+
@latitude = lat
|
213
|
+
end
|
214
|
+
|
215
|
+
# set the longitude for the squeak
|
216
|
+
# must be between @@min_longitude and @@max_longitude
|
217
|
+
def longitude=(longitude)
|
218
|
+
long = longitude.to_f
|
219
|
+
raise "Bad longitude" if long < @@min_longitude
|
220
|
+
raise "Bad longitude" if long > @@max_longitude
|
221
|
+
@longitude = long
|
222
|
+
end
|
223
|
+
|
224
|
+
# set the time to live for the squeak
|
225
|
+
# must be between @@min_duration and @@max_duration
|
226
|
+
def duration=(duration)
|
227
|
+
dur = duration.to_f
|
228
|
+
raise "Bad duration" if dur < @@min_duration
|
229
|
+
raise "Bad duration" if dur > @@max_duration
|
230
|
+
@duration = dur
|
231
|
+
end
|
232
|
+
|
233
|
+
# set the message portion of the squeak
|
234
|
+
# length can't exceed @@max_text_length
|
235
|
+
def text=(txt)
|
236
|
+
raise "Bad text length" unless txt.length <= @@max_text_length
|
237
|
+
@text = txt.dup
|
238
|
+
end
|
239
|
+
|
240
|
+
# simply use to_s on the Hash representation
|
241
|
+
def to_s
|
242
|
+
self.to_hash.to_s
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mapsqueak
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ethan Stryker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-03 00:00:00 +00:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: " A REST client for MapSqueak, a mobile enabled web app. \n"
|
18
|
+
email: e.stryker@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- lib/mapsqueak.rb
|
27
|
+
- bin/squeak.rb
|
28
|
+
has_rdoc: true
|
29
|
+
homepage: http://mapsqueak.rubyforge.org/
|
30
|
+
licenses: []
|
31
|
+
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: mapsqueak
|
52
|
+
rubygems_version: 1.6.2
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: a REST client for MapSqueak
|
56
|
+
test_files: []
|
57
|
+
|