citysdk 0.1.1
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.
- checksums.yaml +15 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +39 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +3 -0
- data/citysdk.gemspec +29 -0
- data/lib/citysdk.rb +9 -0
- data/lib/citysdk/api.rb +216 -0
- data/lib/citysdk/file_reader.rb +387 -0
- data/lib/citysdk/importer.rb +230 -0
- data/lib/citysdk/util.rb +33 -0
- data/spec/api_spec.rb +64 -0
- data/spec/files/csvtest.zip +0 -0
- data/spec/files/geojsonTest.GeoJSON +25 -0
- data/spec/files/hotels.csv +5 -0
- data/spec/files/rk.csv +6 -0
- data/spec/files/shapeTest.zip +0 -0
- data/spec/files/stations.json +42 -0
- data/spec/files/wkb.csv +3 -0
- data/spec/import_spec.rb +137 -0
- metadata +143 -0
| @@ -0,0 +1,230 @@ | |
| 1 | 
            +
            module CitySDK
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              class Importer
         | 
| 4 | 
            +
                attr_reader :filereader, :api
         | 
| 5 | 
            +
                
         | 
| 6 | 
            +
                def initialize(pars)
         | 
| 7 | 
            +
                  @params = pars
         | 
| 8 | 
            +
                  
         | 
| 9 | 
            +
                  raise Exception.new("Missing :host in Importer parameters.") if @params[:host].nil?
         | 
| 10 | 
            +
                  raise Exception.new("Missing :layername in Importer parameters.") if @params[:layername].nil?
         | 
| 11 | 
            +
                  raise Exception.new("Missing :file_path in Importer parameters.") if @params[:file_path].nil?
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  @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])
         | 
| 17 | 
            +
                    @api.release
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  @params[:addresslayer] = 'bag.vbo' if @params[:addressleyer].nil?
         | 
| 21 | 
            +
                  @params[:addressfield] = 'postcode_huisnummer' if @params[:addressfield].nil?
         | 
| 22 | 
            +
                  
         | 
| 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)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                def setLayerStatus(m)
         | 
| 33 | 
            +
                  begin
         | 
| 34 | 
            +
                    sign_in
         | 
| 35 | 
            +
                    @api.set_layer_status(m.gsub("\n","<br/>"))
         | 
| 36 | 
            +
                    sign_out
         | 
| 37 | 
            +
                  rescue Exception => e
         | 
| 38 | 
            +
                    puts "File Importer setLayerStatus Exception #{e.message}"
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                def setParameter(k,v)
         | 
| 43 | 
            +
                  begin
         | 
| 44 | 
            +
                    @params[(k.to_sym rescue k) || k] = v
         | 
| 45 | 
            +
                    return true
         | 
| 46 | 
            +
                  rescue
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                  nil
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def setMatchParameter(l,f,v)
         | 
| 52 | 
            +
                  begin
         | 
| 53 | 
            +
                    @params[:match] = [] if @params[:match].nil?
         | 
| 54 | 
            +
                    @params[:match] << [l,f,v] 
         | 
| 55 | 
            +
                    return true
         | 
| 56 | 
            +
                  rescue
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                  nil
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def sign_in
         | 
| 62 | 
            +
                  if @params[:email].nil?
         | 
| 63 | 
            +
                    raise Exception.new("No credentials provided..")
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                    
         | 
| 66 | 
            +
                  begin
         | 
| 67 | 
            +
                    sign_out if @signed_in
         | 
| 68 | 
            +
                    @api.set_host(@params[:host])
         | 
| 69 | 
            +
                    @api.set_layer(@params[:layername])
         | 
| 70 | 
            +
                    @api.set_matchTemplate(@params[:match_tpl]) if @params[:match_tpl]
         | 
| 71 | 
            +
                    @api.set_createTemplate(@params[:create_tpl]) if @params[:create_tpl]
         | 
| 72 | 
            +
                    @api.authenticate(@params[:email],@params[:passw])
         | 
| 73 | 
            +
                    @signed_in = true
         | 
| 74 | 
            +
                  rescue => e
         | 
| 75 | 
            +
                    @api.release
         | 
| 76 | 
            +
                    raise e
         | 
| 77 | 
            +
                  ensure
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def sign_out
         | 
| 82 | 
            +
                  @signed_in = false
         | 
| 83 | 
            +
                  return @api.release
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              
         | 
| 86 | 
            +
                def filterFields(h)
         | 
| 87 | 
            +
                  data = {}
         | 
| 88 | 
            +
                  h.each_key do |k|
         | 
| 89 | 
            +
                    data[k] = h[k] if @params[:fields].include?(k)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                  data
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              
         | 
| 94 | 
            +
                def doImport(dryrun=false)
         | 
| 95 | 
            +
                  result = {
         | 
| 96 | 
            +
                    :updated => 0,
         | 
| 97 | 
            +
                    :created => 0,
         | 
| 98 | 
            +
                    :not_added => 0
         | 
| 99 | 
            +
                  }
         | 
| 100 | 
            +
                  
         | 
| 101 | 
            +
                  failed = nil
         | 
| 102 | 
            +
                  
         | 
| 103 | 
            +
                  if @params[:hasaddress] == 'certain'
         | 
| 104 | 
            +
                    failed = addToAddress(dryrun)
         | 
| 105 | 
            +
                  # elsif @params[:hasaddress] == 'maybe'
         | 
| 106 | 
            +
                  #   failed = addToAddress(dryrun)
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  if failed == []
         | 
| 110 | 
            +
                    result[:updated] += @filereader.content.length
         | 
| 111 | 
            +
                    return result
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  if failed 
         | 
| 115 | 
            +
                    result[:updated] += (@filereader.content.length - failed.length)
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
                  
         | 
| 118 | 
            +
                  nodes = failed || @filereader.content
         | 
| 119 | 
            +
                  
         | 
| 120 | 
            +
                  count = nodes.length
         | 
| 121 | 
            +
                  
         | 
| 122 | 
            +
                  @api.set_createTemplate(
         | 
| 123 | 
            +
                    {
         | 
| 124 | 
            +
                      :create => {
         | 
| 125 | 
            +
                        :params => { #TODO other create types!!
         | 
| 126 | 
            +
                          :create_type => @params[:create_type],
         | 
| 127 | 
            +
                          :srid => @params[:srid] || 4326
         | 
| 128 | 
            +
                        }
         | 
| 129 | 
            +
                      }
         | 
| 130 | 
            +
                    }
         | 
| 131 | 
            +
                  )
         | 
| 132 | 
            +
                  
         | 
| 133 | 
            +
                  match_tpl = {
         | 
| 134 | 
            +
                    :match => {
         | 
| 135 | 
            +
                      :params => {
         | 
| 136 | 
            +
                        :debug => true,
         | 
| 137 | 
            +
                        :layers => {}
         | 
| 138 | 
            +
                      }
         | 
| 139 | 
            +
                    }
         | 
| 140 | 
            +
                  }
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  begin
         | 
| 143 | 
            +
                    sign_in
         | 
| 144 | 
            +
                    if @params[:unique_id] and @params[:match] and (@params[:hasgeometry] != 'unknown')
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                      match_tpl[:match][:params][:radius] = @params[:radius] || 200
         | 
| 147 | 
            +
                      match_tpl[:match][:params][:geometry_type] = @params[:geometry_type] || :point
         | 
| 148 | 
            +
                      @params[:match].each do |a|
         | 
| 149 | 
            +
                        match_tpl[:match][:params][:layers][a[0]] = {} if match_tpl[:match][:params][:layers][a[0]].nil?
         | 
| 150 | 
            +
                        match_tpl[:match][:params][:layers][a[0]][a[1]] = a[2]
         | 
| 151 | 
            +
                      end
         | 
| 152 | 
            +
                      @api.set_matchTemplate(match_tpl)
         | 
| 153 | 
            +
                      nodes.each do |rec|
         | 
| 154 | 
            +
                        node = {
         | 
| 155 | 
            +
                          :geom => rec[:geometry],
         | 
| 156 | 
            +
                          :id   => rec[:properties][@params[:unique_id]]
         | 
| 157 | 
            +
                        }
         | 
| 158 | 
            +
                        node[:name] = rec[:properties][@params[:name]] if @params[:name]
         | 
| 159 | 
            +
                        node[:data] = rec[:properties]
         | 
| 160 | 
            +
                        @api.match_create_node(node) if not dryrun
         | 
| 161 | 
            +
                        count -= 1
         | 
| 162 | 
            +
                      end
         | 
| 163 | 
            +
                      @api.match_create_flush
         | 
| 164 | 
            +
                  
         | 
| 165 | 
            +
                    elsif @params[:unique_id] and (@params[:hasgeometry] != 'unknown')
         | 
| 166 | 
            +
                      
         | 
| 167 | 
            +
                      begin
         | 
| 168 | 
            +
                        nodes.each do |rec|
         | 
| 169 | 
            +
                          node = {
         | 
| 170 | 
            +
                            :geom => rec[:geometry],
         | 
| 171 | 
            +
                            :id   => rec[:properties][@params[:unique_id]]
         | 
| 172 | 
            +
                          }
         | 
| 173 | 
            +
                          node[:name] = rec[:properties][@params[:name]] if @params[:name]
         | 
| 174 | 
            +
                          node[:data] = rec[:properties]
         | 
| 175 | 
            +
                          @api.create_node(node) if not dryrun
         | 
| 176 | 
            +
                          count -= 1
         | 
| 177 | 
            +
                        end
         | 
| 178 | 
            +
                        @api.create_flush
         | 
| 179 | 
            +
                      rescue => e
         | 
| 180 | 
            +
                        raise e
         | 
| 181 | 
            +
                      end
         | 
| 182 | 
            +
                    else
         | 
| 183 | 
            +
                      raise Exception.new("Cannot import. Geometry or uniuque id is not known for records.") if failed.nil?
         | 
| 184 | 
            +
                    end
         | 
| 185 | 
            +
                  ensure
         | 
| 186 | 
            +
                    a = sign_out
         | 
| 187 | 
            +
                    result[:updated] += a[0]
         | 
| 188 | 
            +
                    result[:created] += a[1]
         | 
| 189 | 
            +
                    result[:not_added] = count
         | 
| 190 | 
            +
                  end
         | 
| 191 | 
            +
                  return result
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def addToAddress(dryrun=false)
         | 
| 195 | 
            +
                  failed = []
         | 
| 196 | 
            +
                  if @params[:postcode] and @params[:housenumber]
         | 
| 197 | 
            +
                    begin
         | 
| 198 | 
            +
                      sign_in
         | 
| 199 | 
            +
                      @filereader.content.each do |rec|
         | 
| 200 | 
            +
                        row = rec[:properties]
         | 
| 201 | 
            +
                        pc = row[@params[:postcode]].downcase.gsub(/[^a-z0-9]/,'')
         | 
| 202 | 
            +
                        hn = row[@params[:housenumber]]
         | 
| 203 | 
            +
                        qres = {}
         | 
| 204 | 
            +
                        if not (pc.empty? or hn.empty?)
         | 
| 205 | 
            +
                          hn.scan(/\d+/).reverse.each { |n|
         | 
| 206 | 
            +
                            qres = @api.get("/nodes?#{@params[:addresslayer]}::#{@params[:addressfield]}=#{pc + n}")
         | 
| 207 | 
            +
                            break if qres[:status]=='success' and qres[:record_count].to_i >= 1
         | 
| 208 | 
            +
                          }
         | 
| 209 | 
            +
                        else
         | 
| 210 | 
            +
                          qres[:status]='nix'
         | 
| 211 | 
            +
                        end
         | 
| 212 | 
            +
                        if qres[:status]=='success' and qres[:results] and qres[:results][0]
         | 
| 213 | 
            +
                          url = '/' + qres[:results][0][:cdk_id] + '/' + @params[:layername]
         | 
| 214 | 
            +
                          n = @api.put(url,{'data'=>filterFields(row)}) if not dryrun
         | 
| 215 | 
            +
                        else
         | 
| 216 | 
            +
                          failed << rec
         | 
| 217 | 
            +
                        end
         | 
| 218 | 
            +
                      end
         | 
| 219 | 
            +
                    rescue => e
         | 
| 220 | 
            +
                      raise e
         | 
| 221 | 
            +
                    ensure
         | 
| 222 | 
            +
                      sign_out
         | 
| 223 | 
            +
                    end
         | 
| 224 | 
            +
                    return failed
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
                  raise Exception.new("Addresses not well defined in dataset.")
         | 
| 227 | 
            +
                end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
              end
         | 
| 230 | 
            +
            end
         | 
    
        data/lib/citysdk/util.rb
    ADDED
    
    | @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class NilClass
         | 
| 4 | 
            +
              def empty?; true; end
         | 
| 5 | 
            +
            end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module CitySDK
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              class Exception < ::Exception
         | 
| 10 | 
            +
                def initialize(message,parms=nil,srcfile=nil,srcline=nil)
         | 
| 11 | 
            +
                  if parms and srcfile and srcline
         | 
| 12 | 
            +
                    file = File.basename( parms[:originalfile] ? parms[:originalfile] : ( parms[:filepath] || '-' ) )
         | 
| 13 | 
            +
                    m = "#{Time.now.strftime("%b %M %Y, %H:%M")}; CitySDK, processing file: #{file}\n Exception in #{File.basename(srcfile)}, #{srcline}\n #{message}"
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    m = "#{Time.now.strftime("%b %M %Y, %H:%M")}; CitySDK Exception: #{message}"
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  super(m)
         | 
| 18 | 
            +
                  $stderr.puts(m) if parms and parms[:verbose]
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def self.parseJson(jsonstring)
         | 
| 23 | 
            +
                begin
         | 
| 24 | 
            +
                  return JSON.parse(jsonstring,{:symbolize_names => true})
         | 
| 25 | 
            +
                rescue Exception => e
         | 
| 26 | 
            +
                  raise CitySDK::Exception.new(e.message)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
    
        data/spec/api_spec.rb
    ADDED
    
    | @@ -0,0 +1,64 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            module CitySDK
         | 
| 4 | 
            +
              TEST_HOST = 'test-api.citysdk.waag.org'
         | 
| 5 | 
            +
              TEST_USER = 'test@waag.org'
         | 
| 6 | 
            +
              TEST_PASS = '123Test321'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              TEST_LAYER = {
         | 
| 9 | 
            +
                :data => {
         | 
| 10 | 
            +
                  :name => 'test.rspec',
         | 
| 11 | 
            +
                  :description => 'for testing',
         | 
| 12 | 
            +
                  :organization => 'waag',
         | 
| 13 | 
            +
                  :category => 'security.test'
         | 
| 14 | 
            +
                }
         | 
| 15 | 
            +
              }
         | 
| 16 | 
            +
              
         | 
| 17 | 
            +
              describe API do
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                before(:each) do
         | 
| 20 | 
            +
                  @api = API.new(TEST_HOST)
         | 
| 21 | 
            +
                  TEST_USER.should_not == 'citysdk@waag.org'
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                after(:each) do
         | 
| 25 | 
            +
                  @api.release
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it "can be connected to" do
         | 
| 29 | 
            +
                  @api.should_not == nil
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it "can be queried" do
         | 
| 33 | 
            +
                  @api.get('/layers')[:status].should == 'success'
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it "can be authorized against" do
         | 
| 37 | 
            +
                  @api.authenticate(TEST_USER,TEST_PASS).should == true
         | 
| 38 | 
            +
                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 | 
            +
             | 
| 46 | 
            +
                it "can not create a layer in an unauthorized domain" do
         | 
| 47 | 
            +
                  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'
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                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'.")
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
              
         | 
| 64 | 
            +
            end
         | 
| Binary file | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "type": "FeatureCollection",
         | 
| 3 | 
            +
              "features": [
         | 
| 4 | 
            +
                { "type": "Feature", 
         | 
| 5 | 
            +
                  "id": "TrajectSensor_Route059", 
         | 
| 6 | 
            +
                  "properties": { 
         | 
| 7 | 
            +
                    "DSSObjectType": "TRAJECT_SENSOR", 
         | 
| 8 | 
            +
                    "LOCATION": "TrajectSensor_Route059", 
         | 
| 9 | 
            +
                    "TIMESTAMP": "13-07-2013 15:45:30", 
         | 
| 10 | 
            +
                    "COLOR": "#00FF00", 
         | 
| 11 | 
            +
                    "VELOCITY": 33, 
         | 
| 12 | 
            +
                    "LENGTH": 961, 
         | 
| 13 | 
            +
                    "TRAVELTIME": 104, 
         | 
| 14 | 
            +
                    "TRAVELTIME_FF": 961
         | 
| 15 | 
            +
                  },  
         | 
| 16 | 
            +
                  "geometry": { 
         | 
| 17 | 
            +
                    "type": "LineString", 
         | 
| 18 | 
            +
                    "coordinates": [ [123289, 487663], [123606, 487587], [123691, 487565], [123792, 487540], [123830, 487520], [123866, 487500], [123888, 487488], [123901, 487479], [123978, 487426], [123982, 487422], [124019, 487394], [124024, 487385], [124037, 487373], [124051, 487358], [124059, 487346], [124067, 487336], [124072, 487316]]
         | 
| 19 | 
            +
                  }
         | 
| 20 | 
            +
                },
         | 
| 21 | 
            +
                { "type": "Feature", "id": "TrajectSensor_Route058", "properties": { "DSSObjectType": "TRAJECT_SENSOR", "LOCATION": "TrajectSensor_Route058", "TIMESTAMP": "13-07-2013 15:45:27", "COLOR": "#00FF00", "VELOCITY": 45, "LENGTH": 961, "TRAVELTIME": 76, "TRAVELTIME_FF": 69},  "geometry": { "type": "LineString", "coordinates": [ [124153, 487283], [124138, 487340], [124119, 487371], [124110, 487384], [124095, 487401], [124091, 487404], [124053, 487430], [124009, 487466], [123929, 487521], [123914, 487531], [123890, 487544], [123853, 487564], [123809, 487586], [123703, 487613], [123618, 487635], [123349, 487699]]}},
         | 
| 22 | 
            +
                { "type": "Feature", "id": "TrajectSensor_Route057", "properties": { "DSSObjectType": "TRAJECT_SENSOR", "LOCATION": "TrajectSensor_Route057", "TIMESTAMP": "13-07-2013 15:44:51", "COLOR": "#FF9900", "VELOCITY": 18, "LENGTH": 3960, "TRAVELTIME": 775, "TRAVELTIME_FF": 285},  "geometry": { "type": "LineString", "coordinates": [ [118925, 483606], [118912, 483647], [118913, 483654], [118918, 483697], [118921, 483731], [118928, 483773], [118933, 483814], [118936, 483834], [118937, 483875], [118937, 483900], [118935, 483921], [118928, 483952], [118921, 483987], [118918, 483997], [118908, 484046], [118889, 484130], [118879, 484176], [118876, 484193], [118874, 484204], [118873, 484206], [118875, 484206], [118873, 484205], [118877, 484207], [118898, 484217], [118916, 484226], [118921, 484228], [118955, 484252], [118958, 484314], [118955, 484460], [118954, 484490], [118953, 484548], [118953, 484647], [118945, 484678], [118931, 484727], [118936, 484719], [118953, 484731], [118965, 484750], [118967, 484762], [118970, 484773], [118964, 484799], [118951, 484817], [118933, 484828], [118910, 484834], [118907, 484824], [118902, 484876], [118891, 484914], [118888, 484928], [118886, 484934], [118879, 484958], [118872, 484986], [118866, 485006], [118861, 485026], [118851, 485072], [118846, 485098], [118843, 485111], [118836, 485145], [118831, 485169], [118819, 485224], [118812, 485254], [118807, 485282], [118803, 485301], [118801, 485318], [118796, 485352], [118793, 485366], [118788, 485390], [118758, 485505], [118753, 485526], [118750, 485535], [118744, 485545], [118750, 485551], [118755, 485575], [118761, 485592], [118776, 485610], [118777, 485612], [118789, 485628], [118800, 485651], [118791, 485659], [118810, 485655], [118909, 485692], [118933, 485702], [119016, 485737], [119056, 485754], [119097, 485771], [119108, 485776], [119141, 485791], [119190, 485809], [119218, 485820], [119319, 485859], [119414, 485897], [119477, 485921], [119588, 485961], [119636, 485980], [119681, 485998], [119738, 486021], [119769, 486034], [119870, 486077], [120009, 486134], [120030, 486142], [120135, 486184], [120143, 486187], [120151, 486191], [120208, 486216], [120330, 486273]]}}
         | 
| 23 | 
            +
              ]
         | 
| 24 | 
            +
            }
         | 
| 25 | 
            +
             | 
| @@ -0,0 +1,5 @@ | |
| 1 | 
            +
            nummer;name;stars;rooms;beds;camping;municipality;town;postcode;street;number;buurt2005;wijk;buurt2010;quarter
         | 
| 2 | 
            +
            1;Eden Amsterdam American Hotel;4;175;354; ;Amsterdam;Amsterdam;1017PN;Leidsekade;97;A07b;A;A07b;A
         | 
| 3 | 
            +
            2;Amstel Intercontinental Amsterdam;5;79;165; ;Amsterdam;Amsterdam;1018GX;Professor Tulpplein;1;A08b;A;A08b;A
         | 
| 4 | 
            +
            3;Amsterdam Centre,nh;4;232;424; ;Amsterdam;Amsterdam;1054ES;Stadhouderskade;7;D22a;D;E22a;E
         | 
| 5 | 
            +
            4;Barbizon Palace,nh;5;274;548; ;Amsterdam;Amsterdam;1012AD;Prins Hendrikkade;59-72;A00a;A;A00a;A
         | 
    
        data/spec/files/rk.csv
    ADDED
    
    | @@ -0,0 +1,6 @@ | |
| 1 | 
            +
            gml_id;bevoegd_gezag;rrgs_id;naam_inrichting;straat;huisnummer;postcode;plaats;gemeente;wm_vergunning;date_changed;longitude;latitude
         | 
| 2 | 
            +
            ID_23;Gemeente ALBRANDSWAARD;12438;RIJNPOORT BV;Ambachtsstraat;5;X176PR;POORTUGAAL;ALBRANDSWAARD;315599;15-05-2009;4.406100015089653;51.85913344374868
         | 
| 3 | 
            +
            ID_24;Gemeente HARDENBERG;3870;Autobedrijf Wessels Dedemsvaart BV.;Langewijk;198; ;DEDEMSVAART;HARDENBERG;90740;07-04-2011;6.464028693395486;52.60686467883884
         | 
| 4 | 
            +
            ID_63;Gemeente PUTTEN;7445;Tankstation Pieper;Broekermolenweg;3;X882MG;PUTTEN;PUTTEN;M07/09;31-01-2011;5.55024558211801;52.2490702463568
         | 
| 5 | 
            +
            ID_9676;Gemeente BOXTEL;1818;Tankstation Texaco Ooiendonk;Rijksweg ;2; ; ;BOXTEL;481;02-02-2011;5.36197249261972;51.55510273583312
         | 
| 6 | 
            +
            ID_9533;Gemeente BEEMSTER;9961;Tankstation B.P. Kruisoord;Rijksweg A7;; ;NOORDBEEMSTER;BEEMSTER;2003-6032;16-01-2012;4.977775378849885;52.58074726262354
         | 
| Binary file | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            [
         | 
| 2 | 
            +
                {
         | 
| 3 | 
            +
                    "alias": "true", 
         | 
| 4 | 
            +
                    "code": "GVC", 
         | 
| 5 | 
            +
                    "country": "NL", 
         | 
| 6 | 
            +
                    "lat": "52.080276", 
         | 
| 7 | 
            +
                    "long": "4.325", 
         | 
| 8 | 
            +
                    "name": "'s-Gravenhage"
         | 
| 9 | 
            +
                }, 
         | 
| 10 | 
            +
                {
         | 
| 11 | 
            +
                    "alias": "true", 
         | 
| 12 | 
            +
                    "code": "ALM", 
         | 
| 13 | 
            +
                    "country": "NL", 
         | 
| 14 | 
            +
                    "lat": "52.37503", 
         | 
| 15 | 
            +
                    "long": "5.21764", 
         | 
| 16 | 
            +
                    "name": "Almere"
         | 
| 17 | 
            +
                }, 
         | 
| 18 | 
            +
                {
         | 
| 19 | 
            +
                    "alias": "true", 
         | 
| 20 | 
            +
                    "code": "APN", 
         | 
| 21 | 
            +
                    "country": "NL", 
         | 
| 22 | 
            +
                    "lat": "52.124443", 
         | 
| 23 | 
            +
                    "long": "4.657778", 
         | 
| 24 | 
            +
                    "name": "Alphen aan den Rijn"
         | 
| 25 | 
            +
                }, 
         | 
| 26 | 
            +
                {
         | 
| 27 | 
            +
                    "alias": "true", 
         | 
| 28 | 
            +
                    "code": "ASD", 
         | 
| 29 | 
            +
                    "country": "NL", 
         | 
| 30 | 
            +
                    "lat": "52.378887", 
         | 
| 31 | 
            +
                    "long": "4.9002776", 
         | 
| 32 | 
            +
                    "name": "Amsterdam"
         | 
| 33 | 
            +
                }, 
         | 
| 34 | 
            +
                {
         | 
| 35 | 
            +
                    "alias": "true", 
         | 
| 36 | 
            +
                    "code": "SHL", 
         | 
| 37 | 
            +
                    "country": "NL", 
         | 
| 38 | 
            +
                    "lat": "52.309444", 
         | 
| 39 | 
            +
                    "long": "4.7619443", 
         | 
| 40 | 
            +
                    "name": "Amsterdam Airport"
         | 
| 41 | 
            +
                }
         | 
| 42 | 
            +
            ]
         | 
    
        data/spec/files/wkb.csv
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
| 1 | 
            +
            "gid";"verkoop_pu";"b_dat_verk";"e_dat_verk";"oms";"domein_cod";"gmrotation";"geom"
         | 
| 2 | 
            +
            18;19184;"2007-02-12";"";"Hofwijckstraat 42 BORD";363;0.259811880644949;"0104000020E61000000100000001010000001960CC67A2661340142840BDAD304A40"
         | 
| 3 | 
            +
            19;19191;"2007-02-12";"";"Spaanse Brabanderstraat 31 BORD";363;0.260326709794243;"0104000020E6100000010000000101000000B7EDEED58C65134069AFCF2E90304A40"
         | 
    
        data/spec/import_spec.rb
    ADDED
    
    | @@ -0,0 +1,137 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            module CitySDK
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              describe "Importer" do
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def newImporter(f)
         | 
| 9 | 
            +
                  @importer = Importer.new({
         | 
| 10 | 
            +
                    :host=>TEST_HOST, 
         | 
| 11 | 
            +
                    :layername=>'test.rspec',
         | 
| 12 | 
            +
                    :file_path => f
         | 
| 13 | 
            +
                  })
         | 
| 14 | 
            +
                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 | 
            +
                
         | 
| 25 | 
            +
                it "checks parameters" do
         | 
| 26 | 
            +
                  expect { Importer.new({:a=>1}) }.to raise_error(CitySDK::Exception)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                it "succesfully creates a FileReader" do
         | 
| 30 | 
            +
                  newImporter('./spec/files/wkb.csv')
         | 
| 31 | 
            +
                  @importer.should_not == nil 
         | 
| 32 | 
            +
                  @importer.filereader.params[:unique_id].should == :gid
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 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 | 
            +
                it "needs authorization to import" do
         | 
| 42 | 
            +
                  newImporter('./spec/files/hotels.csv')
         | 
| 43 | 
            +
                  expect { @importer.doImport }.to raise_error(CitySDK::Exception)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 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
         | 
| 63 | 
            +
             | 
| 64 | 
            +
             | 
| 65 | 
            +
                it "can make a layer and add data to and address" do
         | 
| 66 | 
            +
                  
         | 
| 67 | 
            +
                  newImporter('./spec/files/hotels.csv')
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  @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
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
              
         | 
| 88 | 
            +
              describe "FileReader" do
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                it "can parse json" do
         | 
| 91 | 
            +
                  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"
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                it "can read json files" do
         | 
| 98 | 
            +
                  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
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                it "can read geojson files" do
         | 
| 106 | 
            +
                  fr = FileReader.new({:file_path => './spec/files/geojsonTest.GeoJSON'})
         | 
| 107 | 
            +
                  File.basename(fr.file).should == 'geojsonTest.GeoJSON'
         | 
| 108 | 
            +
                  fr.params[:unique_id].should == nil
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                it "can read csv files" do
         | 
| 112 | 
            +
                  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
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                it "can read csv files with wkb geometry" do
         | 
| 120 | 
            +
                  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
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                it "can read zipped shape files" do
         | 
| 128 | 
            +
                  fr = FileReader.new({:file_path => './spec/files/shapeTest.zip'})
         | 
| 129 | 
            +
                  fr.params[:srid].should == 2100
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
              
         | 
| 134 | 
            +
            end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
             | 
| 137 | 
            +
            # puts JSON.pretty_generate(fr.content[0])
         |