citysdk 0.1.2.5 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/citysdk.gemspec CHANGED
@@ -19,11 +19,12 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
 
21
21
 
22
- gem.add_dependency('dbf')
23
- gem.add_dependency('georuby', '>= 2.0.0')
24
- gem.add_dependency('faraday', '>= 0.8.5')
25
- gem.add_dependency('charlock_holmes', '>= 0.6.9.4')
22
+ gem.add_dependency('dbf', '~> 2.0')
23
+ gem.add_dependency('georuby', '~> 2.0')
24
+ gem.add_dependency('faraday', '~> 0.8')
25
+ gem.add_dependency('charlock_holmes', '~> 0.6')
26
+ gem.add_dependency('curses', '~> 1.0')
26
27
 
27
- gem.add_development_dependency "rspec"
28
+ gem.add_development_dependency "rspec", '~> 3.0'
28
29
  end
29
30
 
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # check the wiki for detailed api usage: https://github.com/waagsociety/citysdk-ld/wiki
4
+
5
+ require 'citysdk'
6
+ include CitySDK
7
+
8
+ api = API.new('api.citysdk.waag.org') # point to a hosted instance of the api.
9
+
10
+ # simple GET
11
+ # GET requests do not need authentication
12
+
13
+ endpoint = api.get '/'
14
+ puts "Enpoint is: #{endpoint[:features][0][:properties][:title]}."
15
+
16
+ first10layers = api.get('/layers')
17
+ puts "First layer: #{JSON.pretty_generate(first10layers[:features][0])}"
18
+
19
+ # find out how many owners the endpoint knows
20
+ owners = api.get('/owners?per_page=1&count')
21
+ puts "Number of data maintaners: #{api.last_result[:headers]['x-result-count']}"
22
+
23
+ # authenticate for write actions.
24
+ unless api.authenticate('<name>','<passw>')
25
+ puts "Did not authenticate..."
26
+ exit
27
+ end
28
+
29
+ # make a layer
30
+ # everybody can wite to the temporary 'test' domain:
31
+
32
+ layer = {
33
+ name: "test.cities",
34
+ owner: "citysdk",
35
+ title: "Cities: 🏠🏢🏣🏨🏫🏬🏭🏡",
36
+ description: "Cities big and small.",
37
+ data_sources: [ "http://fantasy.com" ],
38
+ authoritative: false,
39
+ rdf_type: "dbp:City",
40
+ category: "administrative",
41
+ subcategory: "cities",
42
+ licence: "CC0"
43
+ }
44
+
45
+ api.post('/layers',layer)
46
+
47
+ # add data to this layer
48
+ # attach to the node representing the city of Rotterdam
49
+ object = {type: "Feature",
50
+ geometry: {
51
+ type: 'Point',
52
+ coordinates: [4.4646,51.9222] },
53
+ properties: {
54
+ id: 'Rotterdam',
55
+ title: 'Rotterdam',
56
+ data: {
57
+ a: 1,
58
+ b: 2
59
+ }
60
+ }
61
+ }
62
+
63
+ api.post('/layers/test.cities/objects', object)
64
+
65
+
66
+ # don't forget to release! this will also send 'unfilled' batches to the backend.
67
+ api.release
68
+
data/lib/citysdk/api.rb CHANGED
@@ -1,61 +1,62 @@
1
1
  require 'json'
2
2
  require 'faraday'
3
3
 
4
+
5
+
4
6
  module CitySDK
7
+
8
+ def log(m)
9
+ File.open(File.expand_path('~/csdk.log'), "a") do |f|
10
+ f.write(m + "\n")
11
+ end
12
+ end
5
13
 
6
14
  class HostException < ::Exception
7
15
  end
8
16
 
9
17
  class API
10
- attr_reader :error
18
+ attr_reader :last_result
19
+ attr_reader :error
11
20
  attr_accessor :batch_size
12
-
13
- @@match_tpl = {
14
- :match => {
15
- :params => {}
16
- },
17
- :nodes => []
18
- }
21
+ attr_accessor :page_size
22
+ attr_accessor :format
23
+
19
24
  @@create_tpl = {
20
- :create => {
21
- :params => {
22
- :create_type => "create"
23
- }
24
- },
25
- :nodes => []
25
+ type: "FeatureCollection",
26
+ features: []
26
27
  }
27
28
 
28
29
  def initialize(host, port=nil)
29
30
  @error = '';
30
31
  @layer = '';
31
- @batch_size = 10;
32
+ @batch_size = 1000;
33
+ @page_size = 25;
34
+ @format = 'jsonld'
32
35
  @updated = @created = 0;
33
36
  set_host(host,port)
34
37
  end
35
38
 
36
- def authenticate(e,p)
37
- @email = e;
39
+ def authenticate(n,p)
40
+ @name = n;
38
41
  @passw = p;
39
- if !( @host == 'api.dev' or @host == 'localhost' or @host == '127.0.0.1' or @host == '0.0.0.0')
40
- auth_connection = Faraday.new :url => "https://#{@host}", :ssl => {:verify => false}
41
- resp = auth_connection.get '/get_session', { :e => @email, :p => @passw }
42
- else
43
- resp = @connection.get '/get_session', { :e => @email, :p => @passw }
44
- end
45
- if resp.status == 200
42
+
43
+ resp = @connection.get '/session', { :name => @name, :password => @passw }
44
+ if resp.status.between?(200, 299)
46
45
  resp = CitySDK::parseJson(resp.body)
47
- if resp[:status] == 'success'
48
- @connection.headers['X-Auth'] = resp[:results][0]
46
+ if (resp.class == Hash) and resp[:session_key]
47
+ @connection.headers['X-Auth'] = resp[:session_key]
49
48
  else
50
- raise Exception.new(resp[:message])
49
+ raise Exception.new("Invalid credentials")
51
50
  end
52
51
  else
53
52
  raise Exception.new(resp.body)
54
53
  end
55
-
56
54
  if block_given?
57
- yield
58
- return self.release
55
+ begin
56
+ yield
57
+ ensure
58
+ self.release
59
+ end
59
60
  end
60
61
  true
61
62
  end
@@ -64,6 +65,8 @@ module CitySDK
64
65
  @host = host
65
66
  @port = port
66
67
 
68
+ @host.gsub!(/^http(s)?:\/\//,'')
69
+
67
70
  if port.nil?
68
71
  if host =~ /^(.*):(\d+)$/
69
72
  @port = $2
@@ -73,7 +76,11 @@ module CitySDK
73
76
  end
74
77
  end
75
78
 
76
- @connection = Faraday.new :url => "http://#{@host}:#{@port}"
79
+ if !($nohttps or @host =~ /.+\.dev/ or @host == 'localhost' or @host == '127.0.0.1' or @host == '0.0.0.0')
80
+ @connection = Faraday.new :url => "https://#{@host}", :ssl => {:verify => false }
81
+ else
82
+ @connection = Faraday.new :url => "http://#{@host}:#{@port}"
83
+ end
77
84
  @connection.headers = {
78
85
  :user_agent => 'CitySDK_API GEM ' + CitySDK::VERSION,
79
86
  :content_type => 'application/json'
@@ -84,16 +91,18 @@ module CitySDK
84
91
  raise CitySDK::Exception.new("Trouble connecting to api @ #{host}")
85
92
  end
86
93
  @create = @@create_tpl
87
- @match = @@match_tpl
88
94
  end
89
-
90
- def set_matchTemplate(mtpl)
91
- mtpl[:nodes] = []
92
- @match = @@match_tpl = mtpl
95
+
96
+ def addFormat(path)
97
+ if path !~ /format/
98
+ path = path + ((path =~ /\?/) ? "&" : "?") + "format=#{@format}"
99
+ end
100
+ return path if path =~ /page_size/
101
+ path + "&page_size=#{@page_size}"
93
102
  end
94
103
 
95
104
  def set_createTemplate(ctpl)
96
- ctpl[:nodes] = []
105
+ ctpl[:features] = []
97
106
  @create = @@create_tpl = ctpl
98
107
  end
99
108
 
@@ -101,123 +110,114 @@ module CitySDK
101
110
  @layer = l
102
111
  end
103
112
 
104
- def set_layer_status(status)
105
- put("/layer/#{@layer}/status",{:data => status})
113
+ def next
114
+ @next ? get(@next) : "{}"
106
115
  end
107
-
108
- def match_node(n)
109
- @match[:nodes] << n
110
- return match_flush if @match[:nodes].length >= @batch_size
111
- return nil
116
+
117
+ def layers
118
+ get "/layers"
119
+ end
120
+
121
+ def owners
122
+ get "/owners"
112
123
  end
113
124
 
114
- def match_create_node(n)
115
- @match[:nodes] << n
116
- return match_create_flush if @match[:nodes].length >= @batch_size
125
+ def objects(layer=nil)
126
+ !!layer ? get("/layers/#{layer}/objects") : get("/objects")
117
127
  end
118
128
 
119
- def create_node(n)
120
- @create[:nodes] << n
121
- create_flush if @create[:nodes].length >= @batch_size
129
+ def create_object(n)
130
+ @create[:features] << n
131
+ create_flush if @create[:features].length >= @batch_size
122
132
  end
123
133
 
124
134
  def authorized?
125
- @connection.headers['X-Auth']
135
+ !! @connection.headers['X-Auth']
126
136
  end
127
137
 
128
138
  def release
129
- match_flush
130
139
  create_flush # send any remaining entries in the create buffer
131
- match_create_flush
132
140
  if authorized?
133
- resp = @connection.get('/release_session')
134
- if resp.status == 200
141
+ resp = @connection.delete('/session')
142
+ if resp.status.between?(200, 299)
135
143
  @connection.headers.delete('X-Auth')
136
144
  else
137
- @error = CitySDK::parseJson(resp.body)[:message]
145
+ @error = CitySDK::parseJson(resp.body)[:error]
138
146
  raise HostException.new(@error)
139
147
  end
140
148
  end
141
- return [@updated, @created]
149
+ return {created: @created}
142
150
  end
143
151
 
144
152
  def delete(path)
145
153
  if authorized?
146
- resp = @connection.delete(path)
147
- if resp.status == 200
148
- return CitySDK::parseJson(resp.body)
154
+ resp = @connection.delete(addFormat(path))
155
+ if resp.status.between?(200, 299)
156
+ @last_result = { status: resp.status, headers: resp.headers }
157
+ return (resp.body and resp.body !~ /\s*/) ? CitySDK::parseJson(resp.body) : ''
149
158
  end
150
- @error = CitySDK::parseJson(resp.body)[:message]
159
+ @error = CitySDK::parseJson(resp.body)[:error]
151
160
  raise HostException.new(@error)
152
161
  end
153
- raise CitySDK::Exception.new("DEL needs authorization.")
162
+ raise CitySDK::Exception.new("DELETE needs authorization.")
154
163
  end
155
164
 
156
165
  def post(path,data)
157
166
  if authorized?
158
- resp = @connection.post(path,data.to_json)
159
- return CitySDK::parseJson(resp.body) if resp.status == 200
160
- @error = CitySDK::parseJson(resp.body)[:message]
167
+ resp = @connection.post(addFormat(path),data.to_json)
168
+ @last_result = { status: resp.status, headers: resp.headers }
169
+ return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
170
+ @error = resp.body # CitySDK::parseJson(resp.body)[:error]
171
+
172
+ File.open(File.expand_path("~/post_error_data.json"),"w") do |fd|
173
+ fd.write(JSON.pretty_generate({error: @error, data: data}))
174
+ end
175
+
161
176
  raise HostException.new(@error)
162
177
  end
163
178
  raise CitySDK::Exception.new("POST needs authorization.")
164
179
  end
165
180
 
181
+ def patch(path,data)
182
+ if authorized?
183
+ resp = @connection.patch(addFormat(path),data.to_json)
184
+ @last_result = { status: resp.status, headers: resp.headers }
185
+ return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
186
+ @error = CitySDK::parseJson(resp.body)[:error]
187
+ raise HostException.new(@error)
188
+ end
189
+ raise CitySDK::Exception.new("PATCH needs authorization.")
190
+ end
191
+
166
192
  def put(path,data)
167
193
  if authorized?
168
- resp = @connection.put(path,data.to_json)
169
- return CitySDK::parseJson(resp.body) if resp.status == 200
170
- @error = CitySDK::parseJson(resp.body)[:message]
194
+ resp = @connection.put(addFormat(path),data.to_json)
195
+ @last_result = { status: resp.status, headers: resp.headers }
196
+ return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
197
+ @error = CitySDK::parseJson(resp.body)[:error] || {status: resp.status}
171
198
  raise HostException.new(@error)
172
199
  end
173
200
  raise CitySDK::Exception.new("PUT needs authorization.")
174
201
  end
175
202
 
176
203
  def get(path)
177
- resp = @connection.get(path)
178
- return CitySDK::parseJson(resp.body) if resp.status == 200
179
- @error = CitySDK::parseJson(resp.body)[:message]
204
+ resp = @connection.get(addFormat(path))
205
+ @next = (resp.headers['Link'] =~ /^<(.+)>;\s*rel="next"/) ? $1 : nil
206
+ @last_result = { status: resp.status, headers: resp.headers }
207
+ return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
208
+ @error = CitySDK::parseJson(resp.body)[:error]
180
209
  raise HostException.new(@error)
181
210
  end
182
-
183
- def match_create_flush
184
-
185
- if @match[:nodes].length > 0
186
- resp = post('util/match',@match)
187
- if resp[:nodes].length > 0
188
- @create[:nodes] = resp[:nodes]
189
- res = put("/nodes/#{@layer}",@create)
190
- tally(res)
191
- @create[:nodes] = []
192
- end
193
- @match[:nodes] = []
194
- res
195
- end
196
- nil
197
- end
198
-
199
- def match_flush
200
- if @match[:nodes].length > 0
201
- resp = post('util/match',@match)
202
- @match[:nodes] = []
203
- return resp
204
- end
205
- end
206
-
207
-
211
+
208
212
  def create_flush
209
- if @create[:nodes].length > 0
210
- tally put("/nodes/#{@layer}",@create)
211
- @create[:nodes] = []
213
+ if @create[:features].length > 0
214
+ tally post("/layers/#{@layer}/objects",@create)
215
+ @create[:features] = []
212
216
  end
213
217
  end
214
218
 
215
219
  def tally(res)
216
- if res[:status] == "success"
217
- # TODO: also tally debug data!
218
- @updated += res[:create][:results][:totals][:updated]
219
- @created += res[:create][:results][:totals][:created]
220
- end
220
+ @created += res.length
221
221
  end
222
222
 
223
223
  end