oos4ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ require 'rexml/document'
2
+ require 'rexml/xpath'
3
+
4
+ module Oos4ruby
5
+ class Feed
6
+
7
+ attr_reader :previous, :next, :entries, :xml
8
+
9
+ def initialize(entries, xml)
10
+ @entries = entries
11
+ @xml = xml
12
+ @next = Feed.get_link('next', xml)
13
+ @previous = Feed.get_link 'previous', xml
14
+ @self = Feed.get_link 'self', xml
15
+ end
16
+
17
+ def self.get_link(rel, xml)
18
+ link = REXML::XPath.first(xml, "./atom:link[@rel=\"#{rel}\"]", XmlNamespaces)
19
+ if link
20
+ uri = URI.parse link.attributes['href']
21
+ if uri.absolute?
22
+ return uri
23
+ else
24
+ return URI.parse(OOS_URL).merge(uri)
25
+ end
26
+ end
27
+ end
28
+
29
+ def Feed.read(body)
30
+
31
+ feed = nil
32
+ begin
33
+ feed = REXML::Document.new(body, { :raw => nil }).root
34
+
35
+ entries = REXML::XPath.match(feed, "./atom:entry", XmlNamespaces)
36
+
37
+ entries.map! { |entry| Entry.new(entry) }
38
+ feed = Feed.new( entries, feed )
39
+ rescue => ex
40
+ puts ex.message
41
+ puts ex.backtrace.join("\n")
42
+ end
43
+
44
+ return feed
45
+ end
46
+
47
+ def self_link
48
+ @self
49
+ end
50
+
51
+ def self_link?
52
+ !@self.nil?
53
+ end
54
+
55
+ def previous?
56
+ !@previous.nil?
57
+ end
58
+
59
+ def next?
60
+ !@next.nil?
61
+ end
62
+
63
+ end
64
+ end
65
+
@@ -0,0 +1,140 @@
1
+
2
+ require 'net/http'
3
+
4
+ module Oos4ruby
5
+ class HTTPInvoker
6
+
7
+ attr_reader :response, :headers, :entry, :body
8
+
9
+ def initialize(uri, authent)
10
+ @uri = (uri if uri.kind_of?URI) || URI.parse(uri)
11
+ @authent = authent
12
+
13
+ @headers = {}
14
+ @entry = nil
15
+ end
16
+
17
+ def set_header(name, val)
18
+ @headers[name] = val
19
+ end
20
+
21
+ def get(depth = 0, req = nil)
22
+ return false unless is_authenticate?depth, req
23
+
24
+ http, req = prepare_http req, :get
25
+
26
+ http.start do |connection|
27
+ @response = connection.request(req)
28
+
29
+ return get(depth + 1, req) if need_authentication?(req)
30
+
31
+ if @response.kind_of?Net::HTTPSuccess
32
+ @body = @response.body
33
+ return true
34
+ end
35
+
36
+
37
+ return false
38
+ end
39
+
40
+ end
41
+
42
+ def post(contentType, body, depth = 0, req = nil)
43
+ return false unless is_authenticate?depth, req
44
+
45
+ http, req = prepare_http req, :post
46
+
47
+ req.set_content_type contentType
48
+ @headers.each { |k, v| req[k]= v }
49
+
50
+ http.start do |connection|
51
+ @response = connection.request(req, body)
52
+
53
+ return post(contentType, body, depth + 1, req) if need_authentication?(req)
54
+
55
+ return false if @response.code != '201'
56
+
57
+ begin
58
+ @entry = Entry.new @response.body
59
+ return true
60
+ rescue ArgumentError
61
+ return false
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ def put(contentType, body, depth = 0, req = nil)
68
+ return false unless is_authenticate?depth, req
69
+
70
+ http, req = prepare_http req, :put
71
+
72
+ req.set_content_type contentType
73
+ @headers.each { |k, v| req[k]= v }
74
+
75
+ http.start do |connection|
76
+ @response = connection.request(req, body)
77
+
78
+ return put(contentType, body, depth +1, req) if need_authentication?(req)
79
+
80
+ return true if @response.kind_of? Net::HTTPSuccess
81
+
82
+ return false
83
+ end
84
+
85
+ end
86
+
87
+ def delete( req = nil, depth = 0 )
88
+ return false unless is_authenticate?depth, req
89
+
90
+ http, req = prepare_http req, :delete
91
+
92
+ http.start do |connection|
93
+ @response = connection.request(req)
94
+
95
+ return delete(req, depth + 1) if need_authentication?(req)
96
+
97
+ return true if @response.kind_of? Net::HTTPSuccess
98
+
99
+ return false
100
+ end
101
+
102
+ end
103
+
104
+ private
105
+ def header(which)
106
+ @response[which]
107
+ end
108
+
109
+ def prepare_http( req, option )
110
+ http = Net::HTTP.new(@uri.host, @uri.port)
111
+ http.use_ssl = true if @uri.scheme == 'https'
112
+
113
+ unless req
114
+ url = @uri.path
115
+ url += "?#{@uri.query}" if @uri.query
116
+ req = Net::HTTP::Get.new( url ) if option == :get
117
+ req = Net::HTTP::Post.new( url ) if option == :post
118
+ req = Net::HTTP::Put.new( url ) if option == :put
119
+ req = Net::HTTP::Delete.new( url ) if option == :delete
120
+ end
121
+
122
+ return http, req
123
+ end
124
+
125
+ def need_authentication?(req)
126
+ if @response.instance_of?(Net::HTTPUnauthorized) && @authent
127
+ @authent.add_to req
128
+ req.body = nil unless req.body.nil?
129
+ return true
130
+ end
131
+ return false
132
+ end
133
+
134
+ def is_authenticate?(depth, req)
135
+ return false if depth > 2 and need_authentication?(req)
136
+ return true
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,54 @@
1
+
2
+ require 'rexml/document'
3
+ require 'rexml/xpath'
4
+
5
+ module Oos4ruby
6
+ class Oos
7
+ def auth_app(app_token, secret_key)
8
+ @auth = Auth.new(app_token, secret_key, :app)
9
+ end
10
+
11
+ def auth_user(email, api_token)
12
+ @auth = Auth.new(email, api_token, :wsse)
13
+ document_service
14
+ end
15
+
16
+ def user(slug = nil)
17
+ User.find( @auth, slug )
18
+ end
19
+
20
+ def search(opts)
21
+ Search.find @auth, opts
22
+ end
23
+
24
+ def privacy_cats
25
+ return @privacy_cats if @privacy_cats
26
+ getter = HTTPInvoker.new PRIVACY_URL, @auth
27
+
28
+ worked = getter.get
29
+
30
+ if worked
31
+ @privacy_cats = {}
32
+ cats = REXML::Document.new( getter.body ).root
33
+ REXML::XPath.match(cats, './atom:category', XmlNamespaces).each { |cat|
34
+ cat.add_attribute('scheme', cats.attributes['scheme'])
35
+ @privacy_cats[cat.attributes['term'].underscore.to_sym] = Category.new(cat)
36
+ }
37
+ end
38
+ return @privacy_cats
39
+ end
40
+
41
+ private
42
+ def document_service
43
+ getter = HTTPInvoker.new API_URL, @auth
44
+
45
+ worked = getter.get
46
+
47
+ if worked
48
+ @service = Service.new(REXML::Document.new( getter.body ).root)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+
@@ -0,0 +1,75 @@
1
+
2
+ require 'cgi'
3
+
4
+ module Oos4ruby
5
+ class Search
6
+
7
+ =begin rdoc
8
+ Method to search places into 11870
9
+ available parameters:
10
+ <tt>q</tt>:: string that represents a siple query.
11
+ <tt>bbox</tt>:: array of points that delimiters a rectangle, SW and NE.
12
+ <tt>as</tt>:: area specified by a slug. I.E: /es/madrid.
13
+ <tt>tags</tt>:: array of tags.
14
+ <tt>tag_op</tt>:: tags operator, "and" or "or".
15
+ <tt>lat</tt>:: latitude of the center point of an area.
16
+ <tt>lon</tt>:: longitude of the center point of an area.
17
+ <tt>radius</tt>:: radius to create a rectangle from the center point of an area.
18
+ <tt>page</tt>:: page number in the search results
19
+ =end
20
+ def Search.find(auth, opts)
21
+ query = SEARCH_URL
22
+
23
+ more_params = false
24
+ unless opts.empty?
25
+ query += "?"
26
+ if opts[:q]
27
+ query += "q=#{CGI.escape(opts[:q])}"
28
+ more_params = true
29
+ end
30
+ if opts[:bbox]
31
+ query += "&" if more_params
32
+ query += "bbox=#{opts[:bbox].join(",")}"
33
+ more_params = true
34
+ end
35
+ if opts[:as]
36
+ query += "&" if more_params
37
+ query += "as=#{opts[:as]}"
38
+ more_params = true
39
+ end
40
+ if opts[:tags]
41
+ query += "&" if more_params
42
+ opts[:tags].each_with_index do |tag, index|
43
+ query += "tag=#{CGI.escape(tag)}"
44
+ query += "&" if index < opts[:tags].length - 1
45
+ end
46
+ more_params = true
47
+ end
48
+ if opts[:tag_op]
49
+ query += "&" if more_params
50
+ query += "tagOp=#{opts[:tag_op]}"
51
+ more_params = true
52
+ end
53
+ if opts[:lat] and opts[:lon] and opts[:radius]
54
+ query += "&" if more_params
55
+ query += "lat=#{opts[:lat]}&lon=#{opts[:lon]}&radius=#{opts[:radius]}"
56
+ more_params = true
57
+ end
58
+ if opts[:page]
59
+ query += "&" if more_params
60
+ query += "page=#{opts[:page]}"
61
+ end
62
+ else
63
+ raise RuntimeError('a parameter is obligatory at least')
64
+ end
65
+
66
+ getter = HTTPInvoker.new query, auth
67
+
68
+ worked = getter.get
69
+ raise RuntimeError.new(getter.response.message) unless worked
70
+ Sites.new(Feed.read(getter.body), auth, nil)
71
+ end
72
+ end
73
+ end
74
+
75
+
@@ -0,0 +1,13 @@
1
+ #
2
+ module Oos4ruby
3
+ class Service
4
+
5
+ attr_reader :xml
6
+
7
+ def initialize(xml)
8
+ @xml = xml
9
+ end
10
+ end
11
+ end
12
+
13
+
@@ -0,0 +1,220 @@
1
+
2
+ include Bean
3
+
4
+ module Oos4ruby
5
+ class Site < Bean::BeanClass
6
+
7
+ define_el_reader(
8
+ {
9
+ OosNamespace => [:id, :user_address, :url, :locality, :subadministrativearea, :country, :telephone],
10
+ AppNamespace => [:edited],
11
+ AtomNamespace => [:title, :updated, :summary, :content]
12
+ }
13
+ )
14
+
15
+ define_attr_reader OosNamespace => {:country => :slug, :locality => :slug}
16
+
17
+ alias :oos_id :id
18
+ alias :name :title
19
+ alias :review_title :summary
20
+ alias :review_content :content
21
+
22
+ attr_writer :review_title, :review_content, :user_address, :url, :locality, :telephone
23
+
24
+ def country=(name, slug)
25
+ @country = REXML::Element.new('oos:country')
26
+ @country.add_namespace('oos', OosNamespace)
27
+ @country.add_text name
28
+ @country.add_attribute 'slug', slug
29
+ end
30
+
31
+ def initialize(xml, auth, slug = nil)
32
+ @xml = xml
33
+ @auth = auth
34
+ if slug
35
+ @slug = slug
36
+ @tags_scheme = "#{TAGS_URL}/#{@slug}"
37
+ @lists_scheme = "#{LISTS_URL}/#{@slug}"
38
+ end
39
+ @categories_added = []
40
+ @categories_removed = []
41
+ end
42
+
43
+ def Site.find_by_user( auth, slug, opts = {} )
44
+ raise Oos4ruby::UnknownUser if slug.nil?
45
+
46
+ uri = SITES_URL + "/#{slug}"
47
+
48
+ getter = HTTPInvoker.new uri, auth
49
+
50
+ worked = getter.get
51
+
52
+ Sites.new(Feed.read(getter.body), auth, slug) if worked
53
+ end
54
+
55
+ def Site.dump!(opts, slug)
56
+ entry = create_entry
57
+
58
+ entry.add_element opts[:author]
59
+
60
+ add_element entry, 'updated', DateTime.now
61
+ add_element entry, 'id', make_id
62
+ add_element entry, 'oos:id', opts[:id] if opts[:id]
63
+ add_element entry, 'title', opts[:title] if opts[:title]
64
+ add_element entry, 'oos:useraddress', opts[:user_address] if opts[:user_address]
65
+ add_element entry, 'oos:url', opts[:url] if opts[:url]
66
+ add_element entry, 'summary', opts[:review_title] if opts[:review_title]
67
+ add_element entry, 'summary', opts[:summary] if opts[:summary] and REXML::XPath.first(entry, 'summary', XmlNamespaces).nil?
68
+
69
+ if opts[:privacy]
70
+ if opts[:privacy].is_a?REXML::Element
71
+ entry.add_element opts[:privacy]
72
+ elsif opts[:privacy].is_a?String
73
+ add_category entry, opts[:privacy], PRIVACY_URL
74
+ end
75
+ end
76
+
77
+ if opts[:review_content] || opts[:content]
78
+ content = opts[:review_content] || opts[:content]
79
+ attrs = {}
80
+ text = nil
81
+ if content.is_a?String
82
+ text = content
83
+ elsif content.is_a?Hash
84
+ text = content[:text]
85
+ content.delete :text
86
+ content.each_pair {|key, value| attrs[key.to_s] = value}
87
+ end
88
+ add_element entry, 'content', text, attrs
89
+ end
90
+
91
+ if opts[:locality]
92
+ name = nil
93
+ local_slug = nil
94
+ attrs = {}
95
+ if opts[:locality].is_a?Hash
96
+ name = opts[:locality][:name]
97
+ local_slug = opts[:locality][:slug]
98
+ elsif opts[:locality].is_a?String
99
+ name = opts[:locality]
100
+ end
101
+ attrs['slug'] = local_slug if local_slug
102
+ add_element entry, 'oos:locality', name, attrs
103
+ end
104
+
105
+ if opts[:country]
106
+ name = opts[:country][:name]
107
+ opts[:country].delete :name
108
+ attrs = {}
109
+ opts[:country].each_pair {|key, value| attrs[key.to_s] = value}
110
+ add_element entry, 'oos:country', name, attrs
111
+ end
112
+
113
+ opts[:tags].each { |tag| add_category entry, tag.to_s, "#{TAGS_URL}/#{slug}"} if opts[:tags]
114
+ opts[:lists].each { |list| add_category entry, list.to_s, "#{LISTS_URL}/#{slug}"} if opts[:lists]
115
+
116
+ entry
117
+ end
118
+
119
+ def tags
120
+ return @tags if @tags
121
+ categories = @xml.match("./atom:category[@scheme=\"#{@tags_scheme}\"]")
122
+ if categories
123
+ @tags = categories.map { |cat|
124
+ Category.new cat
125
+ }
126
+ end
127
+ @tags
128
+ end
129
+
130
+ def lists
131
+ return @lists if @lists
132
+ categories = @xml.match("./atom:category[@scheme=\"#{@lists_scheme}\"]")
133
+ if categories
134
+ @lists = categories.map { |cat|
135
+ Category.new cat
136
+ }
137
+ end
138
+ @lists
139
+ end
140
+
141
+ def latitude
142
+ @xml.first('./georss:where/gml:Point/gml:pos').text.
143
+ split[0] if @xml.first('./georss:where')
144
+ end
145
+
146
+ def longitude
147
+ @xml.first('./georss:where/gml:Point/gml:pos').text.
148
+ split[1] if @xml.first('./georss:where')
149
+ end
150
+
151
+ def add_tag(tag)
152
+ tag = Category.new(tag, @tags_scheme )
153
+ @categories_added << tag
154
+ end
155
+
156
+ def add_list(list)
157
+ list = Category.new(list, @lists_scheme )
158
+ @categories_added << list
159
+ end
160
+
161
+ def remove_tag(tag)
162
+ tag = Category.new(tag, @tags_scheme )
163
+ @categories_removed << tag
164
+ end
165
+
166
+ def remove_list(list)
167
+ list = Category.new(list, @lists_scheme )
168
+ @categories_removed << list
169
+ end
170
+
171
+ def privacy
172
+ return @privacy if @privacy
173
+ @privacy = @xml.category({:scheme => PRIVACY_URL}).attributes['term']
174
+ @privacy
175
+ end
176
+
177
+ def privacy=(privacy)
178
+ @privacy_updated = privacy
179
+ end
180
+
181
+ private
182
+ def load!
183
+ if @title_review
184
+ summary = @xml.child('summary') || @xml.add_child('summary')
185
+ summary.text = @title_review
186
+ end
187
+
188
+ if @content_review
189
+ content = @xml.child('content') || @xml.add_child('content', nil, nil, {:type => 'html'})
190
+ content.text = @content_review
191
+ end
192
+
193
+ if @categories_added
194
+ @categories_added.each { |cat|
195
+ add_category cat.term, cat.scheme
196
+ @tags << cat if cat.scheme == @tags_scheme
197
+ @lists << cat if cat.scheme == @lists_scheme
198
+ }
199
+ @categories_added.clear
200
+ end
201
+
202
+ if @categories_removed
203
+ @categories_removed.each { |cat|
204
+ remove_category cat.term, cat.scheme
205
+ @tags = @tags.reject { |tag|
206
+ tag.term == cat.term and tag.scheme == cat.scheme
207
+ }
208
+ }
209
+ @categories_removed.clear
210
+ end
211
+
212
+ update_category @privacy_updated.term, @privacy_updated.scheme,
213
+ nil, @privacy_updated.scheme if @privacy_updated
214
+
215
+ end
216
+
217
+ end
218
+ end
219
+
220
+
@@ -0,0 +1,11 @@
1
+
2
+ module Oos4ruby
3
+ class Sites < Collection
4
+ def initialize(feed, auth, slug = nil)
5
+ super( feed, auth, slug )
6
+ @entries = feed.entries.map {|entry| Site.new(entry, @auth, slug) }
7
+ end
8
+ end
9
+ end
10
+
11
+
@@ -0,0 +1,122 @@
1
+
2
+ require 'mime/types'
3
+
4
+ include Bean
5
+
6
+ module Oos4ruby
7
+ class User < Bean::BeanClass
8
+
9
+ define_el_reader({
10
+ OosNamespace => [:name, :surname, :no_mails, :only_contacts, :no_newsletter],
11
+ AtomNamespace => [:title, :updated, :content]
12
+ })
13
+
14
+ alias :nick :title
15
+ alias :about_me :content
16
+
17
+ attr_writer :nick, :about_me, :name, :surname, :no_mails, :only_contacts, :no_newsletter
18
+
19
+ def initialize(entry, auth, slug = nil)
20
+ @xml = entry
21
+ @auth = auth
22
+ @slug = slug || @xml.child('slug', OosNamespace).text
23
+ end
24
+
25
+ def User.find( auth, slug = nil )
26
+ raise Oos4ruby::UnknownUser if auth.method?(:app) && slug.nil?
27
+
28
+ begin
29
+ uri = URI.parse(slug)
30
+ rescue
31
+ uri = nil
32
+ end
33
+
34
+ unless uri
35
+ uri = USERS_URL
36
+ uri = uri + "/#{slug}" if slug
37
+ end
38
+
39
+ getter = HTTPInvoker.new uri.to_s, auth
40
+
41
+ worked = getter.get
42
+
43
+ if worked
44
+ if slug #response is an Entry
45
+ entry = Entry.new getter.body
46
+ return User.new(entry, auth, slug)
47
+ else
48
+ #response is a feed
49
+ feed = Feed.read getter.body
50
+ rel_edit = feed.entries[0].link('edit')
51
+
52
+ getter = HTTPInvoker.new rel_edit, auth
53
+ worked = getter.get
54
+ if worked
55
+ entry = Entry.new getter.body
56
+ return User.new(entry, auth)
57
+ else
58
+ raise Oos4ruby::UnknownUser
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def to_xml
65
+ @xml.to_s
66
+ end
67
+
68
+ def sites( opts = {} )
69
+ @sites_collection = Site.find_by_user(@auth, @slug, opts) unless @sites_collection
70
+ @sites_collection
71
+ end
72
+
73
+ def contacts( opts = {} )
74
+ @contacts_collection = Contact.find_by_user(@auth, @slug, opts) unless @contacts_collection
75
+ @contacts_collection
76
+ end
77
+
78
+ def avatar
79
+ @xml.link('avatar')
80
+ end
81
+
82
+ def avatar!(file_path)
83
+ getter = HTTPInvoker.new @xml.link('edit-media'), @auth
84
+ worked = getter.get
85
+
86
+ if worked
87
+ file = File.new(file_path, 'w+')
88
+ file << getter.body
89
+ end
90
+ end
91
+
92
+ def update_avatar!(file_path)
93
+ file = File.open(file_path, "rb") { |f| f.read }
94
+
95
+ putter = HTTPInvoker.new(@xml.link('edit-media'), @auth)
96
+
97
+ putter.set_header 'Content-Length', File.size(file_path)
98
+
99
+ worked = putter.put MIME::Types.type_for(file_path)[0].to_s, file
100
+
101
+ raise RuntimeError unless worked
102
+ end
103
+
104
+ private
105
+ def load!
106
+ @xml.child('title').text = @nick if @nick
107
+ if @about_me
108
+ about = @xml.child('content') || @xml.add_child('content', nil, nil, {:type => 'text'})
109
+ about.text = @about_me
110
+ end
111
+
112
+ @xml.child('name', OosNamespace).text = @name if @name
113
+ @xml.child('surname', OosNamespace).text = @surname if @surname
114
+ @xml.child('nomails', OosNamespace).text = @no_mails.to_s if !@no_mails.nil?
115
+ @xml.child('nonewsletter', OosNamespace).text = @no_newsletter.to_s if !@no_newsletter.nil?
116
+ @xml.child('onlycontacts', OosNamespace).text = @only_contacts.to_s if !@only_contacts.nil?
117
+ end
118
+ end
119
+ end
120
+
121
+
122
+
@@ -0,0 +1,9 @@
1
+ module Oos4ruby #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end