citysdk 0.1.2.5 → 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.
@@ -1,9 +1,10 @@
1
+
1
2
  module CitySDK
2
3
 
3
4
  class Importer
4
5
  attr_reader :filereader, :api, :params
5
6
 
6
- def initialize(pars)
7
+ def initialize(pars, fr = nil)
7
8
  @params = pars
8
9
 
9
10
  raise Exception.new("Missing :host in Importer parameters.") if @params[:host].nil?
@@ -11,22 +12,16 @@ module CitySDK
11
12
  raise Exception.new("Missing :file_path in Importer parameters.") if @params[:file_path].nil?
12
13
 
13
14
  @api = CitySDK::API.new(@params[:host])
14
- if @params[:email]
15
- raise Exception.new("Missing :passw in Importer parameters.") if @params[:passw].nil?
16
- raise Exception.new("Failure to authenticate '#{@params[:email]}' with api.") if not @api.authenticate(@params[:email],@params[:passw])
15
+ if @params[:name]
16
+ raise Exception.new("Missing :password in Importer parameters.") if @params[:password].nil?
17
+ raise Exception.new("Failure to authenticate '#{@params[:name]}' with api.") if not @api.authenticate(@params[:name],@params[:password])
17
18
  @api.release
18
19
  end
19
20
 
20
21
  @params[:addresslayer] = 'bag.vbo' if @params[:addressleyer].nil?
21
22
  @params[:addressfield] = 'postcode_huisnummer' if @params[:addressfield].nil?
22
23
 
23
- @params[:create_type] = 'create' if @params[:create_type].nil?
24
- # CREATE_TYPE_UPDATE = 'update'
25
- # CREATE_TYPE_ROUTES = 'routes'
26
- # CREATE_TYPE_CREATE = 'create'
27
-
28
-
29
- @filereader = FileReader.new(@params)
24
+ @filereader = fr || FileReader.new(@params)
30
25
  end
31
26
 
32
27
 
@@ -34,16 +29,6 @@ module CitySDK
34
29
  return @filereader.write(path)
35
30
  end
36
31
 
37
- def setLayerStatus(m)
38
- begin
39
- sign_in
40
- @api.set_layer_status(m.gsub("\n","<br/>"))
41
- sign_out
42
- rescue Exception => e
43
- puts "File Importer setLayerStatus Exception #{e.message}"
44
- end
45
- end
46
-
47
32
  def setParameter(k,v)
48
33
  begin
49
34
  @params[(k.to_sym rescue k) || k] = v
@@ -53,28 +38,12 @@ module CitySDK
53
38
  nil
54
39
  end
55
40
 
56
- def setMatchParameter(l,f,v)
57
- begin
58
- @params[:match] = [] if @params[:match].nil?
59
- @params[:match] << [l,f,v]
60
- return true
61
- rescue
62
- end
63
- nil
64
- end
65
-
66
41
  def sign_in
67
- if @params[:email].nil?
68
- raise Exception.new("No credentials provided..")
69
- end
70
-
71
42
  begin
72
43
  sign_out if @signed_in
73
44
  @api.set_host(@params[:host])
74
45
  @api.set_layer(@params[:layername])
75
- @api.set_matchTemplate(@params[:match_tpl]) if @params[:match_tpl]
76
- @api.set_createTemplate(@params[:create_tpl]) if @params[:create_tpl]
77
- @api.authenticate(@params[:email],@params[:passw])
46
+ @api.authenticate(@params[:name],@params[:password])
78
47
  @signed_in = true
79
48
  rescue => e
80
49
  @api.release
@@ -89,35 +58,32 @@ module CitySDK
89
58
  end
90
59
 
91
60
  def filterFields(h)
92
-
93
- # puts "h: \n#{h}"
94
- # puts "@params[:fields]: \n#{@params[:fields]}"
95
-
96
61
  data = {}
97
62
  h.each_key do |k|
98
63
  k = (k.to_sym rescue k) || k
99
- data[k] = h[k] if @params[:fields].include?(k)
64
+ j = @params[:alternate_fields][k]
65
+ data[j] = h[k] if @params[:fields].include?(k)
100
66
  end
101
- # puts "data: \n#{data}"
102
67
  data
103
68
  end
104
69
 
105
70
 
71
+ def geomToJSON(a)
72
+ # puts JSON.pretty_generate(a)
73
+ a
74
+ end
106
75
 
107
-
108
-
109
- def doImport(dryrun=false, &block)
76
+ def doImport(&block)
110
77
  result = {
111
- :updated => 0,
112
78
  :created => 0,
113
79
  :not_added => 0
114
80
  }
115
81
 
116
82
  failed = nil
117
83
 
118
- if @params[:hasaddress] == 'certain'
119
- failed = addToAddress(dryrun, &block)
120
- end
84
+ # if @params[:hasaddress] == 'certain'
85
+ # failed = addToAddress(&block)
86
+ # end
121
87
 
122
88
  # TODO: add possibility to add node to postal code
123
89
 
@@ -130,72 +96,30 @@ module CitySDK
130
96
  result[:updated] += (@filereader.content.length - failed.length)
131
97
  end
132
98
 
133
- nodes = failed || @filereader.content
134
-
135
- count = nodes.length
136
-
137
- @api.set_createTemplate(
138
- {
139
- :create => {
140
- :params => { #TODO other create types!!
141
- :create_type => @params[:create_type],
142
- :srid => @params[:srid] || 4326
143
- }
144
- }
145
- }
146
- )
147
-
148
- match_tpl = {
149
- :match => {
150
- :params => {
151
- :debug => true,
152
- :layers => {}
153
- }
154
- }
155
- }
99
+ objects = failed || @filereader.content
100
+ count = objects.length
156
101
 
157
102
  begin
158
103
  sign_in
159
- if @params[:unique_id] and @params[:match] and (@params[:hasgeometry] != 'unknown')
160
-
161
- match_tpl[:match][:params][:radius] = @params[:radius] || 200
162
- match_tpl[:match][:params][:geometry_type] = @params[:geometry_type] || :point
163
- @params[:match].each do |a|
164
- match_tpl[:match][:params][:layers][a[0]] = {} if match_tpl[:match][:params][:layers][a[0]].nil?
165
- match_tpl[:match][:params][:layers][a[0]][a[1]] = a[2]
166
- end
167
- @api.set_matchTemplate(match_tpl)
168
- nodes.each do |rec|
169
- node = {
170
- :geom => rec[:geometry],
171
- :id => rec[:id]
172
- }
173
- node[:name] = rec[:properties][@params[:name]] if @params[:name]
174
- node[:data] = filterFields(rec[:properties])
175
-
176
- # puts JSON.pretty_generate(node)
177
-
178
- yield(node) if block_given?
179
-
180
- @api.match_create_node(node) if not dryrun
181
- count -= 1
182
- end
183
- @api.match_create_flush
184
-
185
- elsif @params[:unique_id] and (@params[:hasgeometry] != 'unknown')
186
-
104
+
105
+ if @params[:hasgeometry]
187
106
  begin
188
- nodes.each do |rec|
107
+ objects.each do |record|
108
+
189
109
  node = {
190
- :geom => rec[:geometry],
191
- :id => rec[:id]
110
+ type: 'Feature',
111
+ properties: record[:properties],
112
+ geometry: geomToJSON(record[:geometry]),
192
113
  }
193
- node[:name] = rec[:properties][@params[:name].to_sym] if @params[:name]
194
- node[:data] = filterFields(rec[:properties])
114
+
115
+ node[:properties][:data] = filterFields(record[:properties][:data])
116
+ node[:crs] = { type: 'EPSG', properties: { code: @params[:srid] } } if @params[:srid] != 4326
117
+
118
+ node[:properties][:title] = node[:properties][:data][@params[:title]] if @params[:title]
195
119
 
196
- yield(node) if block_given?
120
+ yield(node[:properties]) if block_given?
197
121
 
198
- @api.create_node(node) if not dryrun
122
+ @api.create_object(node)
199
123
  count -= 1
200
124
  end
201
125
  @api.create_flush
@@ -209,14 +133,13 @@ module CitySDK
209
133
  raise Exception.new(e.message)
210
134
  ensure
211
135
  a = sign_out
212
- result[:updated] += a[0]
213
- result[:created] += a[1]
136
+ result[:created] += a[:created]
214
137
  result[:not_added] = count
215
138
  end
216
139
  return result
217
140
  end
218
141
 
219
- def addToAddress(dryrun=false)
142
+ def addToAddress()
220
143
  failed = []
221
144
  if @params[:postcode] and @params[:housenumber]
222
145
  begin
@@ -240,7 +163,7 @@ module CitySDK
240
163
  url = '/' + qres[:results][0][:cdk_id] + '/' + @params[:layername]
241
164
  data = filterFields(row)
242
165
  yield({addto: qres[:results][0][:cdk_id], data: data}) if block_given?
243
- n = @api.put(url,{'data'=>data}) if not dryrun
166
+ n = @api.put(url,{'data'=>data})
244
167
  else
245
168
  failed << rec
246
169
  end
data/lib/citysdk/util.rb CHANGED
@@ -1,10 +1,32 @@
1
1
  require 'json'
2
2
 
3
- class NilClass
4
- def empty?; true; end
3
+ class String
4
+ def remove_non_ascii
5
+ self.encode( "UTF-8", "binary", :invalid => :replace, :undef => :replace, :replace => '§')
6
+ end
7
+ def starts_with?(aString)
8
+ index(aString) == 0
9
+ end
5
10
  end
6
11
 
12
+ class Object
13
+ def deep_copy
14
+ Marshal.load(Marshal.dump(self))
15
+ end
16
+ def blank?
17
+ return false if self.class == Symbol
18
+ self.nil? or (self.class==String and self.strip == '') or (self.respond_to?(:empty?) ? self.empty? : false)
19
+ end
20
+ end
21
+
22
+
7
23
  module CitySDK
24
+
25
+ # for debugging purposes...
26
+ def jsonlog(o)
27
+ puts JSON.pretty_generate({ o.class.to_s => o })
28
+ end
29
+
8
30
 
9
31
  class Exception < ::Exception
10
32
  def initialize(message,parms=nil,srcfile=nil,srcline=nil)
@@ -21,9 +43,9 @@ module CitySDK
21
43
 
22
44
  def self.parseJson(jsonstring)
23
45
  begin
24
- return JSON.parse(jsonstring,{:symbolize_names => true})
46
+ return jsonstring.blank? ? {} : JSON.parse(jsonstring,symbolize_names: true)
25
47
  rescue Exception => e
26
- raise CitySDK::Exception.new(e.message)
48
+ raise CitySDK::Exception.new("#{e.message}; input: #{jsonstring}")
27
49
  end
28
50
  end
29
51
 
data/lib/citysdk.rb CHANGED
@@ -4,6 +4,6 @@ require 'citysdk/file_reader.rb'
4
4
  require 'citysdk/importer.rb'
5
5
 
6
6
  module CitySDK
7
- VERSION = "0.1.2.5"
7
+ VERSION = "1.0"
8
8
  end
9
9
 
data/spec/api_spec.rb CHANGED
@@ -1,62 +1,69 @@
1
1
 
2
2
 
3
3
  module CitySDK
4
- TEST_HOST = 'test-api.citysdk.waag.org'
5
- TEST_USER = 'test@waag.org'
4
+ TEST_HOST = 'localhost:9292'
5
+ # TEST_HOST = 'test-api.citysdk.waag.org'
6
+ TEST_USER = 'test'
6
7
  TEST_PASS = '123Test321'
7
8
 
9
+ # name=test.rspec title='test layer' owner=citysdk description='for testing' rdf_type=csdk\:Test category=security
10
+
8
11
  TEST_LAYER = {
9
- :data => {
10
- :name => 'test.rspec',
11
- :description => 'for testing',
12
- :organization => 'waag',
13
- :category => 'security.test'
14
- }
12
+ name: "test.rspec",
13
+ title: "test layer",
14
+ owner: TEST_USER,
15
+ description: "for testing",
16
+ data_sources: [""],
17
+ rdf_type: "csdk:Test",
18
+ category: "security",
19
+ subcategory: "test",
20
+ licence: "CC0",
21
+ fields: []
15
22
  }
16
23
 
17
- describe API do
24
+ $api = API.new(TEST_HOST)
18
25
 
19
- before(:each) do
20
- @api = API.new(TEST_HOST)
21
- TEST_USER.should_not == 'citysdk@waag.org'
22
- end
26
+
27
+
28
+ describe API do
23
29
 
24
- after(:each) do
25
- @api.release
26
- end
27
30
 
28
31
  it "can be connected to" do
29
- @api.should_not == nil
32
+ expect($api.class).to be(CitySDK::API)
30
33
  end
31
34
 
32
35
  it "can be queried" do
33
- @api.get('/layers')[:status].should == 'success'
36
+ expect($api.get('/layers').class).to be(Hash)
34
37
  end
35
38
 
36
39
  it "can be authorized against" do
37
- @api.authenticate(TEST_USER,TEST_PASS).should == true
40
+ expect($api.authenticate(TEST_USER,TEST_PASS)).to be(true)
41
+ expect($api.release.class).to be(Array)
42
+ end
43
+
44
+ it "can create and delete a test layer" do
45
+ expect($api.authenticate(TEST_USER,TEST_PASS)).to be(true)
46
+ expect($api.post('/layers',TEST_LAYER)[:features].class).to be(Array)
47
+ expect($api.delete('/layers/test.rspec')).to eq({})
48
+ expect($api.release.class).to be(Array)
38
49
  end
39
-
40
- # it "can create and delete a test layer" do
41
- # @api.authenticate(TEST_USER,TEST_PASS).should == true
42
- # @api.put('/layers',TEST_LAYER)[:status].should == 'success'
43
- # @api.delete('/layer/test.rspec?delete_layer=true')[:status].should == 'success'
44
- # end
45
50
 
46
51
  it "can not create a layer in an unauthorized domain" do
47
52
  h = TEST_LAYER.dup
48
- h[:data][:name] = 'unauthorized.rspec'
49
- @api.authenticate(TEST_USER,TEST_PASS).should == true
50
- expect { @api.put('/layers',h) }.to raise_error(HostException,"Not authorized for domain 'unauthorized'.")
51
- TEST_LAYER[:data][:name] = 'test.rspec'
53
+ h[:name] = 'unauthorized.rsped'
54
+ expect($api.authenticate(TEST_USER,TEST_PASS)).to be(true)
55
+ expect { $api.post('/layers',h) }.to raise_error(HostException,"Owner has no access to domain 'unauthorized'")
56
+ h[:name] = "test.rspec"
57
+ $api.release
52
58
  end
53
59
 
54
60
  it "can not add data to a layer not owned" do
55
- res = @api.get('/nodes?per_page=1')
56
- res[:status].should == 'success'
57
- cdk = res[:results][0][:cdk_id]
58
- @api.authenticate(TEST_USER,TEST_PASS).should == true
59
- expect { @api.put("/#{cdk}/osm",{:data=>{:plop => 'pipo'}}) }.to raise_error(HostException,"Not authorized for layer 'osm'.")
61
+ res = $api.get('/objects?per_page=1')
62
+ expect(res[:type]).to eq('FeatureCollection')
63
+ cdk = res[:features][0][:properties][:cdk_id]
64
+ expect($api.authenticate(TEST_USER,TEST_PASS)).to be(true)
65
+ expect { $api.patch("/objects/#{cdk}/layers/osm",{:plop => 'pipo'}) }.to raise_error(HostException,"Operation requires owners' authorization")
66
+ $api.release
60
67
  end
61
68
 
62
69
  end
data/spec/import_spec.rb CHANGED
@@ -3,82 +3,48 @@
3
3
  module CitySDK
4
4
 
5
5
  describe "Importer" do
6
-
7
-
6
+
8
7
  def newImporter(f)
9
8
  @importer = Importer.new({
10
- :host=>TEST_HOST,
11
- :layername=>'test.rspec',
12
- :file_path => f
9
+ file_path: f,
10
+ host: TEST_HOST,
11
+ layername: TEST_LAYER[:name]
13
12
  })
14
13
  end
15
-
16
- after(:each) do
17
- if @layerCreated
18
- @importer.api.authenticate(TEST_USER,TEST_PASS) do
19
- @importer.api.delete("/layer/test.rspec?delete_layer=true")
20
- end.should_not == nil
21
- end
22
- end
23
-
24
-
14
+
25
15
  it "checks parameters" do
26
16
  expect { Importer.new({:a=>1}) }.to raise_error(CitySDK::Exception)
27
17
  end
28
18
 
29
19
  it "succesfully creates a FileReader" do
30
20
  newImporter('./spec/files/wkb.csv')
31
- @importer.should_not == nil
32
- @importer.filereader.params[:unique_id].should == :gid
21
+ expect(@importer.class).to be(CitySDK::Importer)
22
+ expect(@importer.filereader.params[:unique_id]).to be(:gid)
33
23
  end
34
24
 
35
- it "can add a (match) parameter" do
36
- newImporter('./spec/files/wkb.csv')
37
- @importer.setParameter('freut',:nix).should be_true
38
- @importer.setMatchParameter('freut','pipo',nil).should be_true
39
- end
40
-
41
25
  it "needs authorization to import" do
42
26
  newImporter('./spec/files/hotels.csv')
43
27
  expect { @importer.doImport }.to raise_error(CitySDK::Exception)
44
28
  end
45
29
 
46
- it "can make a match and add data to osm obj" do
47
- newImporter('./spec/files/rk.csv')
48
-
49
- @importer.api.authenticate(TEST_USER,TEST_PASS) do
50
- @importer.api.put('/layers',TEST_LAYER)[:status].should == 'success'
51
- end.should_not == nil
52
- @layerCreated = true
53
- @importer.setParameter(:email,TEST_USER).should be_true
54
- @importer.setParameter(:passw,TEST_PASS).should be_true
55
-
56
- @importer.setMatchParameter('osm','amenity','fuel').should be_true
57
-
58
- res = @importer.doImport[:not_added].should == 0
59
- res = @importer.api.get("/nodes?count&layer=test.rspec")
60
- res[:record_count].should == 5
61
- # puts JSON.pretty_generate(res)
62
- end
30
+ it "can make a layer and delete" do
63
31
 
64
-
65
- it "can make a layer and add data to and address" do
66
-
67
32
  newImporter('./spec/files/hotels.csv')
68
33
 
34
+ @importer.setParameter(:name,TEST_USER)
35
+ @importer.setParameter(:password,TEST_PASS)
36
+ @importer.sign_in
37
+ res = @importer.api.post('/layers',TEST_LAYER)
38
+ expect( (!!res[:features] and res[:features].length == 1) ).to be(true)
39
+ @importer.sign_out
40
+
41
+ expect { @importer.doImport }.to raise_error(CitySDK::Exception)
42
+
43
+ res = @importer.api.get("/layers/test.rspec/objects")
44
+ expect( (!!res[:features] and res[:features].length == 0) ).to be(true)
45
+
69
46
  @importer.api.authenticate(TEST_USER,TEST_PASS) do
70
- @importer.api.put('/layers',TEST_LAYER)[:status].should == 'success'
71
- end.should_not == nil
72
- @layerCreated = true
73
-
74
- @importer.setParameter(:email,TEST_USER).should be_true
75
- @importer.setParameter(:passw,TEST_PASS).should be_true
76
- if TEST_HOST == 'api.citysdk.waag.org'
77
- @importer.doImport[:not_added].should == 0
78
- res = @importer.api.get("/nodes?count&layer=test.rspec")
79
- res[:record_count].should == 4
80
- else
81
- @importer.doImport[:not_added].should == 4
47
+ expect( @importer.api.delete("/layers/#{TEST_LAYER[:name]}") ).to eq({})
82
48
  end
83
49
 
84
50
  end
@@ -89,49 +55,48 @@ module CitySDK
89
55
 
90
56
  it "can parse json" do
91
57
  j = CitySDK::parseJson('{ "arr" : [0,1,1,1], "hash": {"aap": "noot"}, "num": 0 }')
92
- j[:arr].length.should == 4
93
- j[:num].class.should == Fixnum
94
- j[:hash][:aap].should == "noot"
58
+ expect(j[:arr].length).to be(4)
59
+ expect(j[:num].class).to be(Fixnum)
60
+ expect(j[:hash][:aap]).to eq("noot")
95
61
  end
96
62
 
97
63
  it "can read json files" do
98
64
  fr = FileReader.new({:file_path => './spec/files/stations.json'})
99
- File.basename(fr.file).should == 'stations.json'
100
- fr.params[:geomtry_type].should == 'Point'
101
- fr.params[:srid].should == 4326
102
- fr.params[:unique_id].should == :code
65
+ expect(File.basename(fr.file)).to eq('stations.json')
66
+ expect(fr.params[:geomtry_type]).to eq('Point')
67
+ expect(fr.params[:srid]).to be(4326)
68
+ expect(fr.params[:unique_id]).to be(:code)
103
69
  end
104
70
 
105
71
  it "can read geojson files" do
106
72
  fr = FileReader.new({:file_path => './spec/files/geojsonTest.GeoJSON'})
107
- File.basename(fr.file).should == 'geojsonTest.GeoJSON'
108
- fr.params[:unique_id].should == nil
73
+ expect(File.basename(fr.file)).to eq('geojsonTest.GeoJSON')
74
+ expect(fr.params[:unique_id]).to be(:id)#self generated unique id
109
75
  end
110
76
 
111
77
  it "can read csv files" do
112
78
  fr = FileReader.new({:file_path => './spec/files/csvtest.zip'})
113
- File.basename(fr.file).should == 'akw.csv'
114
- fr.params[:srid].should == 4326
115
- fr.params[:colsep].should == ';'
116
- fr.params[:unique_id].should == :ID
79
+ expect(File.basename(fr.file)).to eq('akw.csv')
80
+ expect(fr.params[:srid]).to be(4326)
81
+ expect(fr.params[:colsep]).to eq(';')
82
+ expect(fr.params[:unique_id]).to be(:ID)
117
83
  end
118
84
 
119
85
  it "can read csv files with wkb geometry" do
120
86
  fr = FileReader.new({:file_path => './spec/files/wkb.csv'})
121
- File.basename(fr.file).should == 'wkb.csv'
122
- fr.params[:srid].should == 4326
123
- fr.params[:colsep].should == ';'
124
- fr.params[:unique_id].should == :gid
87
+ expect(File.basename(fr.file)).to eq('wkb.csv')
88
+ expect(fr.params[:srid]).to be(4326)
89
+ expect(fr.params[:colsep]).to eq(';')
90
+ expect(fr.params[:unique_id]).to be(:gid)
125
91
  end
126
92
 
127
93
  it "can read zipped shape files" do
128
94
  fr = FileReader.new({:file_path => './spec/files/shapeTest.zip'})
129
- fr.params[:srid].should == 2100
95
+ expect(fr.params[:srid]).to be(2100)
130
96
  end
131
97
 
132
98
  end
133
-
99
+
134
100
  end
135
101
 
136
102
 
137
- # puts JSON.pretty_generate(fr.content[0])