source: subversion/ruby/api/osm/dao.rb @ 912

Revision 912, 30.6 KB checked in by steve, 8 years ago (diff)

ickle fixes to the traces stuff

Line 
1module OSM
2
3  require 'mysql'
4  require 'singleton'
5  require 'time'
6  require 'osm/servinfo.rb'
7  require 'osm/osmlog.rb'
8
9  class Mercator
10    include Math
11
12    def initialize(lat, lon, degrees_per_pixel, width, height)
13      #init me with your centre lat/lon, the number of degrees per pixel and the size of your image
14      @clat = lat
15      @clon = lon
16      @degrees_per_pixel = degrees_per_pixel
17      @width = width
18      @height = height
19      @dlon = width / 2 * degrees_per_pixel
20      @dlat = height / 2 * degrees_per_pixel  * cos(@clat * PI / 180)
21
22      @tx = xsheet(@clon - @dlon)
23      @ty = ysheet(@clat - @dlat)
24
25      @bx = xsheet(@clon + @dlon)
26      @by = ysheet(@clat + @dlat)
27
28    end
29
30    #the following two functions will give you the x/y on the entire sheet
31
32    def kilometerinpixels
33      return 40008.0  / 360.0 * @degrees_per_pixel
34    end
35
36    def ysheet(lat)
37      log(tan(PI / 4 +  (lat  * PI / 180 / 2)))
38    end
39
40    def xsheet(lon)
41      lon
42    end
43
44    #and these two will give you the right points on your image. all the constants can be reduced to speed things up. FIXME
45
46    def y(lat)
47      return @height - ((ysheet(lat) - @ty) / (@by - @ty) * @height) 
48    end
49
50    def x(lon)
51      return  ((xsheet(lon) - @tx) / (@bx - @tx) * @width) 
52    end
53  end
54
55
56
57
58  class StringIO
59    # helper class for gzip encoding
60    attr_reader :buf
61    def initialize
62      @buf = ''
63    end
64
65    def write(s = '')
66      unless (s.nil?)
67        @buf << s
68        s.length
69      end
70    end
71
72    def length
73      @buf.length
74    end
75    def to_s
76      @buf
77    end
78  end
79
80  class Point
81
82    def initialize(latitude, longitude, id, visible, tags, timestamp=nil)
83      @latitude, @longitude, @id, @visible, @tags, @timestamp = [latitude, longitude, id, visible, tags, timestamp]
84    end
85
86    def to_s
87      "Point #@id at #@latitude, #@longitude, #@visible"
88    end
89
90    attr_reader :latitude, :longitude, :id, :visible, :tags, :timestamp
91
92  end # Point
93
94
95  class Street
96    def initialize(id, tags, segs, visible, timestamp)
97      @id, @tags, @segs, @visible, @timestamp = [id, tags, segs, visible, timestamp]
98    end
99
100    def to_s
101      "Street #{@id} with visible=#{visible}, segs #{segs.to_s} and tags #{tags.to_s}"
102    end
103
104    attr_reader :id, :tags, :segs, :visible, :timestamp
105  end # Street
106
107
108  class Trackpoint
109
110    def initialize(latitude, longitude)
111      @latitude = latitude
112      @longitude = longitude
113    end
114
115    attr_reader :latitude, :longitude
116
117  end
118
119
120  class Linesegment
121    # this is a holding class for holding a segment and its nodes
122    # FIXME this should inherit from UIDLinesegment or something
123    def initialize(id, node_a, node_b, visible, tags, timestamp=nil)
124      @id, @node_a, @node_b, @visible, @node_a_id, @node_b_id, @tags, @timestamp = [id, node_a, node_b, visible, node_a.id, node_b.id, tags, timestamp]
125    end
126
127    def to_s
128      "Linesegment #@id between #{@node_a.to_s} and #{@node_b.to_s}"
129    end
130
131    attr_reader :id, :visible, :node_a, :node_b, :node_a_id, :node_b_id, :tags, :timestamp
132  end #Linesegment
133
134
135
136  class UIDLinesegment
137    # this is a holding class for just a segment and it's node UID's
138    def initialize(id, node_a_id, node_b_id, tags, visible=false, timestamp=nil)
139      @id, @node_a_id, @node_b_id, @tags, @visible, @timestamp = [id, node_a_id, node_b_id, tags, visible, timestamp]
140    end
141
142    def to_s
143      "UIDLinesegment #@id between #@node_a_id and #@node_b_id"
144    end
145
146    attr_reader :id, :node_a_id, :node_b_id, :tags, :visible, :timestamp
147
148  end #UIDLinesegment
149
150
151
152  class Dao
153    include Singleton
154
155    @@log = Osmlog.instance
156
157    def mysql_error(e)
158      puts "Error code: ", e.errno, "\n"
159      puts "Error message: ", e.error, "\n"
160      @@log.log("Error code: " + e.errno.to_s)
161      @@log.log("Error message: "+ e.error)
162    end
163
164    def get_connection
165      begin
166        return Mysql.real_connect($DBSERVER, $USERNAME, $PASSWORD, $DATABASE)
167
168      rescue MysqlError => e
169        mysql_error(e)
170
171      end
172
173    end
174
175    ## quote
176    # escape characters in the string which might affect the
177    # mysql query
178    def quote(string)
179      return Mysql.quote(string)
180    end
181
182    def q(s); quote(s); end
183
184
185    ## check_user?
186    # returns whether the given username and password are correct and active
187    def check_user?(email, pass)
188      @@log.log('checking user ' + email)
189
190      res = call_sql { "select id from users where email='#{q(email)}' and pass_crypt=md5('#{q(pass)}') and active = true" }
191      # should only be one result, as user name is unique
192      if res.num_rows == 1
193        set_timeout(email)
194        return true
195      end
196      # otherwise, return false
197      return false
198    end
199
200
201    def make_token
202      chars = 'abcdefghijklmnopqrtuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
203
204      confirmstring = ''
205
206      30.times do
207        confirmstring += chars[(rand * chars.length).to_i].chr
208      end
209
210      return confirmstring
211    end
212
213
214    def call_sql
215      dbh = nil
216      begin
217        dbh = get_connection
218        sql = yield
219        @@log.log sql
220        res = dbh.query(sql)
221        if res.nil? then return true else return res end
222      rescue MysqlError =>ex
223        mysql_error(ex)
224      ensure
225        dbh.close unless dbh.nil?
226      end
227      nil
228    end
229
230
231    def set_timeout(email)
232      call_sql { "update users set timeout = NOW() + INTERVAL 1 DAY where email = '#{q(email)}' and active = true" }
233    end
234
235
236    def logout(user_id)
237      @@log.log("logging out user #{user_id}")
238      call_sql { "update users set token = '#{make_token()}' where id = '#{user_id}' and active = true" }
239    end
240
241
242    def activate_account(email, token)
243      email = quote(email)
244      token = quote(token)
245
246      begin
247        dbh = get_connection
248
249        dbh.query("update users set active = true where email = '#{email}' and token = '#{token}' and active = false")
250
251        result = dbh.query("select * from users where email = '#{email}' and token = '#{token}' and active = true")
252
253        return result.num_rows == 1
254
255
256      rescue MysqlError => e
257        mysql_error(e)
258
259      ensure
260        dbh.close if dbh
261      end
262
263      return false
264
265    end
266
267
268    def create_account(email, pass)
269      @@log.log 'creating account for ' + email.to_s
270      if !does_user_exist?(email)
271        token = make_token
272        res = call_sql { "insert into users(email, timeout, token, active, pass_crypt, creation_time) values ('#{q(email)}', NOW(), '#{q(token)}', false, md5('#{pass}'), NOW())" }
273
274        if res.nil?
275          return ''
276        else
277          return token
278        end
279      end
280      return ''
281    end
282
283
284    def set_token_for_user(email)
285      token = make_token
286      call_sql { "update users set token = '#{token}' where email = '#{q(email)}' and active = true" }
287      return token
288    end 
289
290
291    def login(email, pass)
292      if check_user?(email,pass)
293        token = make_token
294        res = call_sql { "update users set token = '#{token}' where email = '#{q(email)}' and pass_crypt=md5('#{q(pass)}') and active = true" }
295
296        if res.nil?
297          return ''
298        else
299          set_timeout(email)
300          return token
301        end
302      end
303      return ''
304    end
305
306
307    def set_password_for_user(email, pass, token)
308      return call_sql { "update users set pass_crypt = md5('#{q(pass)}') where email = '#{q(email)}' and token = '#{q(token)}' and active = true" }
309    end
310
311
312    def does_user_exist?(email)
313      res = call_sql { "select id from users where email = '#{q(email)}' and active = true" }
314      return res.num_rows == 1
315    end
316
317
318    ## check_user_token?
319    # checks a user token to see if it is active
320    def check_user_token?(token)
321      res = call_sql { "select id from users where active = 1 and token = '#{q(token)}' and timeout > NOW()" }
322      if res.num_rows == 1
323        res.each_hash do |row|
324          return row['id'].to_i
325        end
326      end
327      # otherwise, return false
328      return false
329    end
330
331
332    def set_cookie(r,token)
333      ed = (Time.now + (60 * 60 * 24)).rfc2822()
334      r.headers_out.add('Set-Cookie', 'openwaymap=' + token + '; path=/; expires=' + ed)
335    end
336
337
338    def check_cookie?(cgi)
339      cvalues = cgi.cookies['openwaymap']
340      if !cvalues.empty?
341        token = cvalues[0]
342        if token
343          user_id = check_user_token?(token)
344        end
345      end
346      return [token,user_id]
347    end
348
349
350    def email_from_token(token)
351      res = call_sql { "select email from users where active = 1 and token = '#{q(token)}'" }
352
353      if res.nil?
354        return nil
355      end
356
357      if res.num_rows == 1
358        res.each_hash do |row|
359          return row['email']
360        end
361      end
362
363    end
364
365
366    def save_display_name(user_id, display_name)   
367      res = call_sql { "select id from users where display_name = '#{q(display_name)}'" }
368      return false if res.num_rows > 0
369      call_sql {"update users set display_name = '#{q(display_name)}' where id = #{user_id}"}
370      return true 
371    end
372
373   
374    def details_from_user_id(user_id)
375      res = call_sql { "select email, display_name from users where active = 1 and id = #{user_id}" }
376
377      if res.nil?
378        return nil
379      end
380
381      if res.num_rows == 1
382        res.each_hash do |row|
383          return {'display_name' => row['display_name'], 'email' => row['email'] }
384        end
385      end
386    end
387
388    def details_from_email(email)
389      res = call_sql { "select email, display_name from users where active = 1 and email = '#{email}'" }
390
391      if res.nil?
392        return nil
393      end
394
395      if res.num_rows == 1
396        res.each_hash do |row|
397          return {'display_name' => row['display_name'], 'email' => row['email'] }
398        end
399      end
400    end
401
402
403
404   
405    def gpx_ids_for_user(user_id)
406      return call_sql { "select id from gpx_files where user_id = #{q(user_id.to_s)}" }
407    end
408
409    def gpx_files(bpublic, display_name, tag, user_id, page=0, limit=false)
410      clause = ''
411      clause += ' and private = 0 ' if bpublic
412      clause += " and user_id = #{q(user_id.to_s)} " if user_id.to_i != 0
413      clause += " and gpx_files.user_id in (select id from users where display_name='#{q(display_name)}') " if display_name != ''
414      clause += " and gpx_files.id in (select gpx_id from gpx_file_tags where tag='#{q(tag)}') " if tag != ''
415
416      limit = ''
417      limit = ' limit 20 ' if limit==true
418     
419      return call_sql { "
420        select * from (
421        select gpx_files.inserted, gpx_files.id, gpx_files.timestamp, gpx_files.name, gpx_files.size, gpx_files.latitude, gpx_files.longitude, gpx_files.private, gpx_files.description, users.display_name from gpx_files, users where visible = 1 and gpx_files.user_id = users.id and users.display_name != '' #{clause} order by timestamp desc) as a left join (select gpx_id,group_concat(tag SEPARATOR ' ') as tags from gpx_file_tags group by gpx_id) as t  on a.id=t.gpx_id #{limit}" }
422       
423    end
424
425    def gpx_get(user_id, gpx_id)
426      return call_sql { "select id, timestamp, name, size, latitude, longitude, private, description from gpx_files where user_id = #{q(user_id.to_s)} and id = #{q(gpx_id.to_s)} and visible = 1" }
427    end
428
429    def gpx_public_get(gpx_id)
430      return call_sql { "select users.display_name, gpx_files.id, gpx_files.timestamp, gpx_files.name, gpx_files.size, gpx_files.latitude, gpx_files.longitude, gpx_files.private, gpx_files.description from gpx_files, users  where gpx_files.id = #{q(gpx_id.to_s)} and gpx_files.visible = 1 and gpx_files.private = 0 and gpx_files.user_id = users.id" }
431    end
432
433    def gpx_tags(gpx_id)
434      res = call_sql { "select tag from gpx_file_tags where gpx_id = #{q(gpx_id.to_s)} order by sequence_id asc" }
435      tags = []
436      res.each { |tag| tags << tag[0] }
437      return tags
438    end
439
440    def gpx_user_tags(user_id)
441      return call_sql { "select distinct tag from gpx_file_tags where gpx_id in (select id from gpx_files where user_id = #{q(user_id.to_s)} and visible=1) order by tag;" }
442    end
443
444    def gpx_update_desc(gpx_id, description='', tags=[])
445      call_sql { "update gpx_files set description = '#{q(description)}' where id = #{q(gpx_id.to_s)}" }
446      call_sql { "delete from gpx_file_tags where gpx_id = #{q(gpx_id.to_s)}" }
447
448      tags.split.each do |tag|
449        call_sql { "insert into gpx_file_tags (gpx_id, tag) values (#{q(gpx_id.to_s)}, '#{q(tag.to_s)}')" }
450      end
451    end
452
453    def gpx_pending_details_for_user(user_id)
454      @@log.log('getting gpx files for user ' + user_id.to_s)
455      return call_sql { "select originalname from gpx_pending_files where user_id = #{q(user_id.to_s)}" }
456    end
457
458    def gpx_set_private(gpx_id, private=false)
459      call_sql { "update gpx_files set private=#{q(private.to_s)} where id=#{q(gpx_id.to_s)}" }
460    end
461
462    def gpx_size(gpx_id)
463      res = call_sql { "select count(*) as count from gps_points where gpx_id = #{q(gpx_id.to_s)}" }
464      res.each_hash do |row|
465        return row['count']
466      end
467    end
468
469
470    def does_user_own_gpx?(user_id, gpx_id)
471      res = call_sql { "select id from gpx_files where user_id = #{q(user_id.to_s)} and id = #{q(gpx_id.to_s)} and visible = 1" }
472      return res && res.num_rows == 1
473    end
474
475    def gpx_public?(gpx_id)
476      res = call_sql { "select id from gpx_files where id = #{q(gpx_id.to_s)} and private = 0 and visible = 1" }
477      return res && res.num_rows == 1
478    end
479
480
481
482    def schedule_gpx_delete(gpx_id)
483      call_sql { "update gpx_files set visible = false where id = #{q(gpx_id.to_s)}" }
484    end
485
486
487    def schedule_gpx_upload(originalname, tmpname, user_id, description, tags)
488      begin
489        dbh = get_connection
490
491        dbh.query( "insert into gpx_files (name, tmpname, user_id, description, visible, inserted, timestamp, size) values ('#{q(originalname)}', '#{q(tmpname)}', #{user_id}, '#{description}', 1, 0, NOW(), 0)")
492        res = dbh.query( "select last_insert_id()")
493
494        gpx_id = -1
495
496        res.each do |row|
497          gpx_id = row[0].to_i
498        end
499       
500        gpx_update_desc(gpx_id, description, tags) unless gpx_id == 0
501       
502      rescue MysqlError => e
503        mysql_error(e)
504
505      ensure
506        dbh.close if dbh
507      end
508       
509    end
510
511
512    def get_scheduled_gpx_uploads()
513      call_sql { "select * from gpx_files where inserted = 0" }
514    end
515
516    def delete_sheduled_gpx_files()
517      call_sql { 'delete from gpx_files, gps_points using gpx_files, gps_points where gpx_files.id = gps_points.gpx_id and gpx_files.visible = false' }
518    end   
519
520
521    def new_gpx_file(user_id, filename)
522
523      begin
524        dbh = get_connection
525        dbh.query("insert into gpx_files (timestamp, user_id, visible, name) values (NOW(), #{q(user_id.to_s)}, 1, '#{q(filename.to_s)}')")
526        res = dbh.query('select last_insert_id()') 
527
528        res.each do |row|
529          return row[0]
530        end
531
532        return -1
533      rescue MysqlError => e
534        mysql_error(e)
535
536      ensure
537        dbh.close if dbh
538      end
539      return nil
540    end
541
542    def update_gpx_meta(gpx_id)
543      call_sql { "update gpx_files set size = (select count(*) from gps_points where gps_points.gpx_id = #{gpx_id}) where id = #{gpx_id};" }
544      call_sql { "update gpx_files set latitude = (select latitude from gps_points where gps_points.gpx_id = #{gpx_id} limit 1),
545                    longitude = (select longitude from gps_points where gps_points.gpx_id = #{gpx_id} limit 1) where id = #{gpx_id};" }
546    end
547
548
549    def useridfromcreds(email, pass)
550      if email == 'token'
551        id = check_user_token?(pass)
552        if id
553          return id
554        else
555          return -1
556        end
557      else
558        useridfromemail(email)
559      end
560    end
561
562
563    def useridfromemail(email)
564      email = quote(email)
565
566      begin
567        dbh = get_connection
568        res = dbh.query("select id from users where email='#{email}' and active = true")
569
570        res.each_hash do |row|
571          return row['id'].to_i
572        end
573
574        return -1
575      rescue MysqlError => e
576        mysql_error(e)
577
578      ensure
579        dbh.close if dbh
580      end
581    end
582
583
584    def getnodes(lat1, lon1, lat2, lon2, to=nil)
585      nodes = {}
586
587      timeclause = get_time_clause(nil, to).gsub('timestamp','nodes.timestamp')
588
589      res = call_sql { "select id, latitude, longitude, visible, tags from (select * from (select nodes.id, nodes.latitude, nodes.longitude, nodes.visible, nodes.tags from nodes, nodes as a where a.latitude > #{lat2}  and a.latitude < #{lat1}  and a.longitude > #{lon1} and a.longitude < #{lon2} #{timeclause} and nodes.id = a.id order by nodes.timestamp desc) as b group by id) as c where visible = true and latitude > #{lat2}  and latitude < #{lat1}  and longitude > #{lon1} and longitude < #{lon2}" }
590
591      if !res.nil?
592        res.each_hash do |row|
593
594          node_id = row['id'].to_i
595          nodes[node_id] = Point.new(row['latitude'].to_f, row['longitude'].to_f, node_id, true, row['tags'])
596        end
597
598        return nodes
599      end
600
601    end
602
603
604    def get_nodes_by_ids(node_ids, to=nil)
605       nodes = {}
606       timeclause = get_time_clause(nil, to)
607
608       res = call_sql { "select id, latitude, longitude, visible, tags from
609         (select * from
610          (select id, latitude, longitude, visible, tags from nodes where nodes.id in (#{node_ids.join(',')}) #{timeclause} order by id, timestamp desc) as a group by id) as b" }
611
612      if !res.nil?
613        res.each_hash do |row|
614          node_id = row['id'].to_i
615          vis = '1' == row['visible']
616          nodes[node_id] = Point.new(row['latitude'].to_f, row['longitude'].to_f, node_id, vis, row['tags'])
617        end
618
619        return nodes
620      end 
621
622    end
623   
624
625
626
627    def getnodesbydate(lat1, lon1, lat2, lon2, date)
628      nodes = {}
629
630      res = call_sql { "select id, latitude, longitude, visible, tags from (select * from (select nodes.id, nodes.latitude, nodes.longitude, nodes.visible, nodes.tags from nodes, nodes as a where a.latitude > #{lat2}  and a.latitude < #{lat1}  and a.longitude > #{lon1} and a.longitude < #{lon2} and date < #{date.strftime('%Y-%m-%d %H:%M:%S')} and nodes.id = a.id order by nodes.timestamp desc) as b group by id) as c where visible = true and latitude > #{lat2}  and latitude < #{lat1}  and longitude > #{lon1} and longitude < #{lon2} and date < #{date.strftime('%Y-%m-%d %H:%M:%S')}" }
631
632      if !res.nil?
633        res.each_hash do |row|
634
635          node_id = row['id'].to_i
636          nodes[node_id] = Point.new(row['latitude'].to_f, row['longitude'].to_f, node_id, true, row['tags'])
637        end
638
639        return nodes
640      end
641
642    end
643
644    #{date.strftime('%Y-%m-%d %H:%M:%S')}
645
646
647    def get_track_points(lat1, lon1, lat2, lon2, page)
648      points = Array.new
649
650      page = page * 5000
651
652      res = call_sql { "select distinctrow latitude, longitude from gps_points where latitude > #{lat1} and latitude < #{lat2} and longitude > #{lon1} and longitude < #{lon2} order by timestamp desc limit #{page}, 5000" }
653
654      return nil unless res
655
656      res.each_hash do |row|
657        points.push Trackpoint.new(row['latitude'].to_f, row['longitude'].to_f)
658      end
659      return points
660    end
661
662
663    def get_gpx_points(gpx_id)
664      points = Array.new
665
666      begin
667
668        dbh = get_connection
669
670        q = "select latitude, longitude from gps_points where gpx_id = #{gpx_id} limit 5000"
671
672        res = dbh.query(q)
673
674        res.each_hash do |row|
675          points.push Trackpoint.new(row['latitude'].to_f, row['longitude'].to_f)
676        end
677
678        return points
679
680      rescue MysqlError => e
681        mysql_error(e)
682
683      ensure
684        dbh.close if dbh
685      end
686
687    end
688
689
690
691    def getlines(nodes, to=nil)
692
693      timeclause = get_time_clause(nil, to)
694      ids = nodes.collect { |id, node| id }
695      cbuff = "(#{ids.join(',')})"
696      begin
697        conn = get_connection
698
699        q = "SELECT segment.id, segment.node_a, segment.node_b, segment.tags FROM (
700               select * from
701                  (SELECT * FROM segments where (node_a IN #{cbuff} OR node_b IN #{cbuff}) #{timeclause} ORDER BY timestamp DESC)
702               as a group by id) as segment where visible = true"
703
704        @@log.log q
705        res = conn.query(q)
706
707        segments = {}
708
709        res.each_hash do |row|
710          segment_id = row['id'].to_i
711          segments[segment_id] = UIDLinesegment.new(segment_id, row['node_a'].to_i, row['node_b'].to_i, row['tags'])
712        end
713
714        return segments
715
716      rescue MysqlError => e
717        mysql_error(e)
718      ensure
719        conn.close if conn
720      end
721
722    end
723
724
725    def getlinesbydate(nodes, date)
726      clausebuffer = "("
727      first = true
728
729      nodes.each do |node_id, p|
730        if !first
731          clausebuffer += ',' + node_id.to_s
732        else
733          clausebuffer += node_id.to_s
734          first = false
735        end
736
737      end
738      clausebuffer += ')'
739
740      begin
741        conn = get_connection
742
743        q = "SELECT segment.id, segment.node_a, segment.node_b, segment.tags FROM (
744               select * from
745                  (SELECT * FROM segments where node_a IN #{clausebuffer} OR node_b IN #{clausebuffer} ORDER BY timestamp DESC)
746               as a group by id) as segment where visible = true and date < #{date.strftime('%Y-%m-%d %H:%M:%S')}"
747
748        res = conn.query(q)
749
750        segments = {}
751
752        res.each_hash do |row|
753          segment_id = row['id'].to_i
754          segments[segment_id] = UIDLinesegment.new(segment_id, row['node_a'].to_i, row['node_b'].to_i, row['tags'])
755        end
756
757        return segments
758
759      rescue MysqlError => e
760        mysql_error(e)
761      ensure
762        conn.close if conn
763      end
764
765    end
766
767
768    def getnode(node_id)
769      res = call_sql {"select latitude, longitude, visible, tags from nodes where id=#{node_id} order by timestamp desc limit 1" }
770
771      if !res.nil?
772        res.each_hash do |row|
773          visible = false
774
775          if row['visible'] == '1' then visible = true end
776
777          return Point.new(row['latitude'].to_f, row['longitude'].to_f, node_id, visible, row['tags'])
778        end
779
780        return nil
781
782      end
783    end
784
785
786    def delete_node?(node_id, user_id)
787
788      begin
789        dbh = get_connection
790        res = dbh.query("select latitude, longitude from nodes where id = #{node_id} order by timestamp desc limit 1")
791
792        res.each_hash do |row|
793          dbh.query("insert into nodes (id,latitude,longitude,timestamp,user_id,visible) values (#{node_id} , #{row['latitude']}, #{row['longitude']}, NOW(), #{user_id}, 0)")
794          return true
795        end
796
797      rescue MysqlError => e
798        mysql_error(e)
799
800      ensure
801        dbh.close if dbh
802      end
803
804      return false
805    end 
806
807
808    def update_node?(node_id, user_id, latitude, longitude, tags)
809      call_sql { "insert into nodes (id,latitude,longitude,timestamp,user_id,visible,tags) values (#{node_id} , #{latitude}, #{longitude}, NOW(), #{user_id}, 1, '#{q(tags)}')" }
810    end
811
812
813    def create_node(lat, lon, user_id, tags)
814      @@log.log("creating node at #{lat},#{lon} for user #{user_id} with tags '#{tags}'")
815      begin
816        dbh = get_connection
817
818        dbh.query( "insert into meta_nodes (timestamp, user_id) values (NOW(), #{user_id})" )
819
820        dbh.query( "insert into nodes (id, latitude, longitude, timestamp, user_id, visible, tags) values ( last_insert_id(), #{lat}, #{lon}, NOW(), #{user_id}, 1, '#{q(tags)}')" )
821
822        res = dbh.query( "select last_insert_id() " )
823
824        res.each do |row|
825          @@log.log 'returning new node id ' + row[0].to_s
826          return row[0]
827        end
828
829      rescue MysqlError =>ex
830        mysql_error(ex)
831      ensure
832        dbh.close unless dbh.nil?
833      end
834
835      return -1
836    end
837
838
839    def create_segment(node_a_id, node_b_id, user_id, tags)
840      @@log.log("Creating segment #{node_a_id} -> #{node_b_id} for user #{user_id} with tags '#{tags}'")
841      begin
842        dbh = get_connection
843
844        sql = "insert into meta_segments (timestamp, user_id) values (NOW() , #{user_id})"
845        dbh.query(sql)
846
847        sql = "insert into segments (id, node_a, node_b, timestamp, user_id, visible, tags) values (last_insert_id(), #{node_a_id}, #{node_b_id}, NOW(), #{user_id},1, '#{q(tags)}')"
848        dbh.query(sql)
849
850        res = dbh.query('select last_insert_id()')
851
852        res.each do |row|
853          return row[0]
854        end
855
856        return -1
857      rescue MysqlError => e
858        mysql_error(e)
859
860      ensure
861        dbh.close if dbh
862      end
863      return nil
864    end
865
866
867    def update_segment?(segment_id, user_id, node_a, node_b, tags)
868      call_sql { "insert into segments (id, node_a, node_b, timestamp, user_id, visible, tags) values (#{q(segment_id.to_s)}, #{q(node_a.to_s)}, #{q(node_b.to_s)}, NOW(), #{q(user_id.to_s)}, 1, '#{q(tags)}')" }
869    end
870
871
872    def getsegment(segment_id)
873      res = call_sql { "select node_a, node_b, visible, tags from segments where id=#{segment_id} order by timestamp desc limit 1" }
874
875      res.each_hash do |row|
876        visible = false
877        if row['visible'] == '1' then visible = true end
878        return Linesegment.new(segment_id, getnode(row['node_a'].to_i), getnode(row['node_b'].to_i), visible, row['tags'])
879      end
880      return nil
881    end # getsegment
882
883
884    def delete_segment?(segment_id, user_id)
885
886      begin
887        dbh = get_connection
888        res = dbh.query("select node_a, node_b from segments where id = #{q(segment_id.to_s)} order by timestamp desc limit 1")
889
890        res.each_hash do |row|
891          dbh.query("insert into segments (id,node_a,node_b,timestamp,user_id,visible) values (#{q(segment_id.to_s)} , #{row['node_a']}, #{row['node_b']}, NOW(), #{user_id}, 0)")
892          return true
893        end
894
895      rescue MysqlError => e
896        mysql_error(e)
897
898      ensure
899        dbh.close if dbh
900      end
901
902      return false
903    end # deletesegment
904
905
906    def get_multi(multi_id, type=:way, version=nil)
907      clause = ' order by version desc limit 1;'
908      clause = " and version = #{version} " unless version.nil?
909      res = call_sql { "select version, visible, timestamp from #{type}s where id = #{q(multi_id.to_s)} " + clause }
910
911      version = 0
912      visible = true
913      timestamp = ''
914      res.each_hash do |row|
915        version = row['version'].to_i
916        timestamp = row['timestamp']
917        visible = false unless row['visible'] == '1'
918      end
919
920      return nil unless version != 0
921
922      res = call_sql { "select k,v from #{type}_tags where id = #{q(multi_id.to_s)} and version = #{version};" }
923
924      tags = []
925      res.each_hash do |row|
926        tags << [row['k'],row['v']]
927      end
928
929      res = call_sql { "select segment_id as n from #{type}_segments where id = #{q(multi_id.to_s)} and version = #{version};" }
930
931      segs = []
932      res.each_hash do |row|
933        segs << [row['n'].to_i]
934      end
935
936      return Street.new(multi_id, tags, segs, visible, timestamp)
937    end # get_multi
938
939
940    def update_multi(user_id, tags, segs, type=:way, new=false, multi_id=0)
941
942      begin
943        dbh = get_connection
944        dbh.query( "set @ins_time = NOW();" )
945        dbh.query( "set @user_id = #{q(user_id.to_s)};" )
946
947
948        if new
949          dbh.query( "insert into meta_#{type}s (user_id, timestamp) values (@user_id, @ins_time)" )
950          dbh.query( "set @id = last_insert_id() ")
951        else
952          return nil unless get_multi(multi_id, type)
953          dbh.query("set @id = #{multi_id}")
954        end
955
956        dbh.query( "insert into #{type}s (id, user_id, timestamp) values (@id, @user_id, @ins_time)" )
957        dbh.query( "set @version = last_insert_id()")
958
959        tags_sql = "insert into #{type}_tags(id, k, v, version) values "
960        first = true
961        tags.each do |k,v|
962          tags_sql += ',' unless first
963          first = false unless !first
964          tags_sql += "(@id, '#{q(k.to_s)}', '#{q(v.to_s)}', @version)"
965        end
966
967        dbh.query( tags_sql )
968
969        segs_sql = "insert into #{type}_segments (id, segment_id, version) values "
970
971        first = true
972        segs.each do |n|
973          segs_sql += ',' unless first
974          first = false unless !first
975          segs_sql += "(@id, #{q(n.to_s)}, @version)"
976        end
977
978        dbh.query( segs_sql )
979
980        res = dbh.query( "select @id as id" )
981
982        res.each_hash do |row|
983          return row['id'].to_i
984        end
985      rescue MysqlError =>ex
986        mysql_error(ex)
987      ensure
988        dbh.close unless dbh.nil?
989      end
990
991      return nil
992
993    end
994
995    def new_multi(user_id, tags, segs, type=:way)
996      return update_multi(user_id, tags, segs, type, true)
997    end
998
999    def delete_multi(multi_id, user_id, type=:way)
1000      multi = get_multi(multi_id, type)
1001      call_sql { "insert into #{type}s (id, user_id, timestamp, visible) values (#{q(multi_id.to_s)}, #{q(user_id.to_s)},NOW(),0)" }
1002    end
1003
1004    def get_node_history(node_id, from=nil, to=nil)
1005      res = call_sql { "select latitude as lat, longitude as lon, visible, tags, timestamp from nodes where id = #{node_id} " + get_time_clause(from, to) }
1006      history = []
1007      res.each_hash do |row|
1008        visible = '1' == row['visible']
1009        history << Point.new( row['lat'], row['lon'], node_id, visible, row['tags'], row['timestamp'] )
1010      end
1011      return history
1012    end 
1013
1014    def get_segment_history(segment_id, from=nil, to=nil)
1015                           
1016      res = call_sql { "select node_a, node_b, visible, tags, timestamp from segments where id = #{segment_id} " + get_time_clause(from,to) }
1017      history = []
1018      res.each_hash do |row|
1019        visible = '1' == row['visible']
1020        history << UIDLinesegment.new(segment_id, row['node_a'], row['node_b'], row['tags'], visible, row['timestamp'] )
1021      end
1022      return history
1023    end 
1024
1025    def get_multi_history(multi_id, type=:way, from=nil, to=nil) 
1026      res = call_sql { "select version from #{type}s where id = #{multi_id} " + get_time_clause(from,to) }
1027      history = []
1028      res.each_hash do |row|
1029        visible = '1' == row['visible']
1030        history << get_multi(multi_id, type, row['version'].to_i)
1031      end
1032      return history
1033    end
1034
1035    def get_time_clause(from, to)
1036      clause = ''
1037      clause += " and timestamp > '#{from.strftime('%Y-%m-%d %H:%M:%S')}' " unless from.nil?
1038      clause += " and timestamp < '#{  to.strftime('%Y-%m-%d %H:%M:%S')}' " unless to.nil?
1039      return clause   
1040    end
1041
1042    def get_multis_from_segments(segment_ids, type=:way)
1043      segment_clause = "(#{segment_ids.join(',')})"
1044      res = call_sql { "
1045      select g.id from #{type}s as g,
1046        (select id, max(version) as version from #{type}s where id in
1047          (select distinct a.id from
1048            (select id, max(version) as version from #{type}_segments where id in (select id from #{type}_segments where segment_id in #{segment_clause}) group by id) as a
1049          ) group by id
1050         ) as b where g.id = b.id and g.version = b.version and g.visible = 1 "}
1051         
1052      multis = []
1053
1054      res.each_hash do |row|
1055        multis << get_multi( row['id'].to_i, type )
1056      end
1057      return multis
1058    end
1059
1060    def commify(number)
1061      c = { :value => "", :length => 0 }
1062      r = number.to_s.reverse.split("").inject(c) do |t, e| 
1063        iv, il = t[:value], t[:length]
1064        iv += ',' if il % 3 == 0 && il != 0   
1065        { :value => iv + e, :length => il + 1 }
1066      end
1067      r[:value].reverse!
1068    end
1069  end
1070end
1071
Note: See TracBrowser for help on using the repository browser.