oos4ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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