]> git.openstreetmap.org Git - rails.git/commitdiff
Resyncing from head 10895:11795
authorShaun McDonald <shaun@shaunmcdonald.me.uk>
Sat, 8 Nov 2008 11:52:58 +0000 (11:52 +0000)
committerShaun McDonald <shaun@shaunmcdonald.me.uk>
Sat, 8 Nov 2008 11:52:58 +0000 (11:52 +0000)
12 files changed:
1  2 
app/controllers/diary_entry_controller.rb
app/controllers/user_controller.rb
app/models/diary_entry.rb
app/views/browse/start.rjs
config/routes.rb
db/migrate/017_add_timestamp_indexes.rb
db/migrate/018_populate_node_tags_and_remove.rb
db/migrate/018_populate_node_tags_and_remove_helper.c
db/migrate/019_move_to_innodb.rb
db/migrate/020_key_constraints.rb
db/migrate/021_add_changesets.rb
public/javascripts/map.js

index a965af2ffb51d463b5e59d398e905b7b78d89abf,e0d6e44cdd8764f4aacc39bfcf8d664ca38ee83e..d9f5e4253fedab9391f3b869e11f017c72e6218c
@@@ -54,7 -54,7 +54,7 @@@ class DiaryEntryController < Applicatio
  
    def list
      if params[:display_name]
 -      @this_user = User.find_by_display_name(params[:display_name], :conditions => "visible = 1")
 +      @this_user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
  
        if @this_user
          @title = @this_user.display_name + "'s diary"
@@@ -69,7 -69,8 +69,8 @@@
        end
      else
        @title = "Users' diaries"
-       @entry_pages, @entries = paginate(:diary_entries,
+       @entry_pages, @entries = paginate(:diary_entries, :include => :user,
+                                         :conditions => "users.visible = 1",
                                          :order => 'created_at DESC',
                                          :per_page => 20)
      end
@@@ -77,7 -78,7 +78,7 @@@
  
    def rss
      if params[:display_name]
 -      user = User.find_by_display_name(params[:display_name], :conditions => "visible = 1")
 +      user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
  
        if user
          @entries = DiaryEntry.find(:all, :conditions => ['user_id = ?', user.id], :order => 'created_at DESC', :limit => 20)
@@@ -90,7 -91,9 +91,9 @@@
          render :nothing => true, :status => :not_found
        end
      else
-       @entries = DiaryEntry.find(:all, :order => 'created_at DESC', :limit => 20)
+       @entries = DiaryEntry.find(:all, :include => :user,
+                                  :conditions => "users.visible = 1",
+                                  :order => 'created_at DESC', :limit => 20)
        @title = "OpenStreetMap diary entries"
        @description = "Recent diary entries from users of OpenStreetMap"
        @link = "http://www.openstreetmap.org/diary"
    end
  
    def view
 -    user = User.find_by_display_name(params[:display_name], :conditions => "visible = 1")
 +    user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
  
      if user
        @entry = DiaryEntry.find(:first, :conditions => ['user_id = ? AND id = ?', user.id, params[:id]])
index 196d5cea66267c8e552649a6db2fd49320ad021c,c658b201412a5bf2dda750e292458b38c945c1aa..b9ed5409658ac85a614124961f54ee1da77f6f12
@@@ -16,6 -16,7 +16,7 @@@ class UserController < ApplicationContr
      @user.visible = true
      @user.data_public = true
      @user.description = "" if @user.description.nil?
+     @user.creation_ip = request.remote_ip
  
      if @user.save
        flash[:notice] = "User was successfully created. Check your email for a confirmation note, and you\'ll be mapping in no time :-)<br>Please note that you won't be able to login until you've received and confirmed your email address."
@@@ -76,7 -77,7 +77,7 @@@
    def lost_password
      @title = 'lost password'
      if params[:user] and params[:user][:email]
 -      user = User.find_by_email(params[:user][:email], :conditions => "visible = 1")
 +      user = User.find_by_email(params[:user][:email], :conditions => {:visible => true})
  
        if user
          token = user.tokens.create
    end
  
    def view
 -    @this_user = User.find_by_display_name(params[:display_name], :conditions => "visible = 1")
 +    @this_user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
  
      if @this_user
        @title = @this_user.display_name
    def make_friend
      if params[:display_name]     
        name = params[:display_name]
 -      new_friend = User.find_by_display_name(name, :conditions => "visible = 1")
 +      new_friend = User.find_by_display_name(name, :conditions => {:visible => true})
        friend = Friend.new
        friend.user_id = @user.id
        friend.friend_user_id = new_friend.id
    def remove_friend
      if params[:display_name]     
        name = params[:display_name]
 -      friend = User.find_by_display_name(name, :conditions => "visible = 1")
 +      friend = User.find_by_display_name(name, :conditions => {:visible => true})
        if @user.is_friends_with?(friend)
          Friend.delete_all "user_id = #{@user.id} AND friend_user_id = #{friend.id}"
          flash[:notice] = "#{friend.display_name} was removed from your friends."
index fe48ee8dce01b50213dd72c05878f2e78c60c67c,dd1f9882a7a4726ffff14147292b1891a0584893..c20788fbbe7858b6056d5773ae2183a5941b0d2e
@@@ -1,10 -1,10 +1,12 @@@
  class DiaryEntry < ActiveRecord::Base
    belongs_to :user
-   has_many :diary_comments, :order => "id"
+   has_many :diary_comments, :include => :user,
+                             :conditions => "users.visible = 1",
+                             :order => "diary_comments.id"
  
    validates_presence_of :title, :body
 +  validates_length_of :title, :within => 1..255
 +  validates_length_of :language, :within => 2..3
    validates_numericality_of :latitude, :allow_nil => true
    validates_numericality_of :longitude, :allow_nil => true
    validates_associated :user
index e257005a360ba993fd1ddc249f80a7af01024558,c17325ad19c6a94b1b87e245d39ee3fabc8e0f01..f38b1dc80937cb0c9f6355236fd87a2b50b01e49
@@@ -15,6 -15,8 +15,8 @@@ page << <<EO
    OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
      
    function startBrowse() {
+     browseActive = true;
      openSidebar({ onclose: stopBrowse });
  
      var vectors = new OpenLayers.Layer.Vector();
@@@ -32,8 -34,6 +34,6 @@@
  
      map.events.register("moveend", map, showData);
      map.events.triggerEvent("moveend");
-     browseActive = true;
    }
  
    function showData() {
      return false;
    }    
  
-   function customDataLoader(request) { 
+   function customDataLoader(request) {
      if (browseActive) {
        var doc = request.responseXML;
  
      if (size > 0.25) {
        setStatus("Unable to load: Bounding box size of " + size + " is too large (must be smaller than 0.25)");
      } else {
 -      loadGML("/api/0.5/map?bbox=" + projected.toBBOX());
 +      loadGML("/api/#{API_VERSION}/map?bbox=" + projected.toBBOX());
      }
    }
  
        map.addLayer(browseDataLayer);
              
        browseSelectControl = new OpenLayers.Control.SelectFeature(browseDataLayer, { onSelect: onFeatureSelect });
-       browseSelectControl.handler.stopDown = false;
-       browseSelectControl.handler.stopUp = false;
+       browseSelectControl.handlers.feature.stopDown = false;
+       browseSelectControl.handlers.feature.stopUp = false;
        map.addControl(browseSelectControl);
        browseSelectControl.activate();
      } else {
      this.link.href = "";
      this.link.innerHTML = "Wait...";
  
 -    new Ajax.Request("/api/0.5/" + this.type + "/" + this.feature.osm_id + "/history", {
 +    new Ajax.Request("/api/#{API_VERSION}/" + this.type + "/" + this.feature.osm_id + "/history", {
        onComplete: OpenLayers.Function.bind(displayHistory, this)
      });
  
diff --combined config/routes.rb
index 139611bc6132ede96fddf37c4bde040c804ee569,b7d570980de7876f3f344848e215527a289e74b2..91130b9b01d2d209a2213ddb39963dfe89972ed0
@@@ -1,19 -1,10 +1,19 @@@
  ActionController::Routing::Routes.draw do |map|
  
    # API
 +  map.connect "api/capabilities", :controller => 'api', :action => 'capabilities'
 +  
 +  map.connect "api/#{API_VERSION}/changeset/create", :controller => 'changeset', :action => 'create'
 +  map.connect "api/#{API_VERSION}/changeset/:id/upload", :controller => 'changeset', :action => 'upload', :id => /\d+/
 +  map.connect "api/#{API_VERSION}/changeset/:id/download", :controller => 'changeset', :action => 'download', :id => /\d+/
 +  map.connect "api/#{API_VERSION}/changeset/:id", :controller => 'changeset', :action => 'read', :id => /\d+/
 +  map.connect "api/#{API_VERSION}/changeset/:id/close", :controller => 'changeset', :action => 'close', :id =>/\d+/
 +  
    map.connect "api/#{API_VERSION}/node/create", :controller => 'node', :action => 'create'
    map.connect "api/#{API_VERSION}/node/:id/ways", :controller => 'way', :action => 'ways_for_node', :id => /\d+/
    map.connect "api/#{API_VERSION}/node/:id/relations", :controller => 'relation', :action => 'relations_for_node', :id => /\d+/
    map.connect "api/#{API_VERSION}/node/:id/history", :controller => 'old_node', :action => 'history', :id => /\d+/
 +  map.connect "api/#{API_VERSION}/node/:id/:version", :controller => 'old_node', :action => 'version', :id => /\d+/, :version => /\d+/
    map.connect "api/#{API_VERSION}/node/:id", :controller => 'node', :action => 'read', :id => /\d+/, :conditions => { :method => :get }
    map.connect "api/#{API_VERSION}/node/:id", :controller => 'node', :action => 'update', :id => /\d+/, :conditions => { :method => :put }
    map.connect "api/#{API_VERSION}/node/:id", :controller => 'node', :action => 'delete', :id => /\d+/, :conditions => { :method => :delete }
    map.connect "api/#{API_VERSION}/way/:id/history", :controller => 'old_way', :action => 'history', :id => /\d+/
    map.connect "api/#{API_VERSION}/way/:id/full", :controller => 'way', :action => 'full', :id => /\d+/
    map.connect "api/#{API_VERSION}/way/:id/relations", :controller => 'relation', :action => 'relations_for_way', :id => /\d+/
 +  map.connect "api/#{API_VERSION}/way/:id/:version", :controller => 'old_way', :action => 'version', :id => /\d+/, :version => /\d+/
    map.connect "api/#{API_VERSION}/way/:id", :controller => 'way', :action => 'read', :id => /\d+/, :conditions => { :method => :get }
    map.connect "api/#{API_VERSION}/way/:id", :controller => 'way', :action => 'update', :id => /\d+/, :conditions => { :method => :put }
    map.connect "api/#{API_VERSION}/way/:id", :controller => 'way', :action => 'delete', :id => /\d+/, :conditions => { :method => :delete }
    map.connect "api/#{API_VERSION}/ways", :controller => 'way', :action => 'ways', :id => nil
  
 -  map.connect "api/#{API_VERSION}/capabilities", :controller => 'api', :action => 'capabilities'
    map.connect "api/#{API_VERSION}/relation/create", :controller => 'relation', :action => 'create'
    map.connect "api/#{API_VERSION}/relation/:id/relations", :controller => 'relation', :action => 'relations_for_relation', :id => /\d+/
    map.connect "api/#{API_VERSION}/relation/:id/history", :controller => 'old_relation', :action => 'history', :id => /\d+/
@@@ -63,8 -54,8 +63,9 @@@
    
    # Potlatch API
    
-   map.connect "api/#{API_VERSION}/amf", :controller =>'amf', :action =>'talk'
+   map.connect "api/#{API_VERSION}/amf/read", :controller =>'amf', :action =>'amf_read'
+   map.connect "api/#{API_VERSION}/amf/write", :controller =>'amf', :action =>'amf_write'
 +  map.connect "api/#{API_VERSION}/amf", :controller =>'amf', :action =>'talk'
    map.connect "api/#{API_VERSION}/swf/trackpoints", :controller =>'swf', :action =>'trackpoints'
    
    # Data browsing
@@@ -76,7 -67,6 +77,7 @@@
    map.connect '/browse/node/:id/history', :controller => 'browse', :action => 'node_history', :id => /\d+/
    map.connect '/browse/relation/:id', :controller => 'browse', :action => 'relation', :id => /\d+/
    map.connect '/browse/relation/:id/history', :controller => 'browse', :action => 'relation_history', :id => /\d+/
 +  map.connect '/browse/changeset/:id', :controller => 'browse', :action => 'changeset', :id => /\d+/
    
    # web site
  
index c6b3bc7c2cd3e303f606dabd234483bcd6750b1b,0000000000000000000000000000000000000000..c6b3bc7c2cd3e303f606dabd234483bcd6750b1b
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
 +class AddTimestampIndexes < ActiveRecord::Migration
 +  def self.up
 +    add_index :current_ways, :timestamp, :name => :current_ways_timestamp_idx
 +    add_index :current_relations, :timestamp, :name => :current_relations_timestamp_idx
 +  end
 +
 +  def self.down
 +    remove_index :current_ways, :name => :current_ways_timestamp_idx
 +    remove_index :current_relations, :name => :current_relations_timestamp_idx
 +  end
 +end
index f10bf16d2c53075c10e409c10a5cf610baf8a8d8,0000000000000000000000000000000000000000..f10bf16d2c53075c10e409c10a5cf610baf8a8d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,60 -1,0 +1,60 @@@
 +class PopulateNodeTagsAndRemove < ActiveRecord::Migration
 +  def self.up
 +    have_nodes = select_value("SELECT count(*) FROM current_nodes").to_i != 0
 +
 +    if have_nodes
 +      prefix = File.join Dir.tmpdir, "017_populate_node_tags_and_remove.#{$$}."
 +
 +      cmd = "db/migrate/017_populate_node_tags_and_remove_helper"
 +      src = "#{cmd}.c"
 +      if not File.exists? cmd or File.mtime(cmd) < File.mtime(src) then 
 +        system 'cc -O3 -Wall `mysql_config --cflags --libs` ' +
 +          "#{src} -o #{cmd}" or fail
 +      end
 +
 +      conn_opts = ActiveRecord::Base.connection.instance_eval { @connection_options }
 +      args = conn_opts.map { |arg| arg.to_s } + [prefix]
 +      fail "#{cmd} failed" unless system cmd, *args
 +
 +      tempfiles = ['nodes', 'node_tags', 'current_nodes', 'current_node_tags'].
 +        map { |base| prefix + base }
 +      nodes, node_tags, current_nodes, current_node_tags = tempfiles
 +    end
 +
 +    execute "TRUNCATE nodes"
 +    remove_column :nodes, :tags
 +    remove_column :current_nodes, :tags
 +
 +    add_column :nodes, :version, :bigint, :limit => 20, :null => false
 +
 +    create_table :current_node_tags, innodb_table do |t|
 +      t.column :id,          :bigint, :limit => 64, :null => false
 +      t.column :k,         :string, :default => "", :null => false
 +      t.column :v,         :string, :default => "", :null => false
 +    end
 +
 +    create_table :node_tags, innodb_table do |t|
 +      t.column :id,          :bigint, :limit => 64, :null => false
 +      t.column :version,     :bigint, :limit => 20, :null => false
 +      t.column :k,         :string, :default => "", :null => false
 +      t.column :v,         :string, :default => "", :null => false
 +    end
 +
 +    # now get the data back
 +    csvopts = "FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY '\"' LINES TERMINATED BY '\\n'"
 +
 +    if have_nodes
 +      execute "LOAD DATA INFILE '#{nodes}' INTO TABLE nodes #{csvopts} (id, latitude, longitude, user_id, visible, timestamp, tile, version)";
 +      execute "LOAD DATA INFILE '#{node_tags}' INTO TABLE node_tags #{csvopts} (id, version, k, v)"
 +      execute "LOAD DATA INFILE '#{current_node_tags}' INTO TABLE current_node_tags #{csvopts} (id, k, v)"
 +    end
 +
 +    tempfiles.each { |fn| File.unlink fn } if have_nodes
 +  end
 +
 +  def self.down
 +    raise IrreversibleMigration.new
 +#    add_column :nodes, "tags", :text, :default => "", :null => false
 +#    add_column :current_nodes, "tags", :text, :default => "", :null => false
 +  end
 +end
index 697b8fcd3321a2b8351334bdc2448f117782191b,0000000000000000000000000000000000000000..83c1b174367fd0ac4b473ed8f7939914614d1a1b
mode 100644,000000..100644
--- /dev/null
@@@ -1,241 -1,0 +1,241 @@@
-     fprintf(stderr, "017_populate_node_tags_and_remove_helper: MySQL error: %s\n", err);
 +#include <mysql.h>
 +#include <stdint.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +static void exit_mysql_err(MYSQL *mysql) {
 +  const char *err = mysql_error(mysql);
 +  if (err) {
-     fprintf(stderr, "017_populate_node_tags_and_remove_helper: MySQL error\n");
++    fprintf(stderr, "018_populate_node_tags_and_remove_helper: MySQL error: %s\n", err);
 +  } else {
-     printf("Usage: 017_populate_node_tags_and_remove_helper host user passwd database port socket prefix\n");
++    fprintf(stderr, "018_populate_node_tags_and_remove_helper: MySQL error\n");
 +  }
 +  abort();
 +  exit(EXIT_FAILURE);
 +}
 +
 +static void write_csv_col(FILE *f, const char *str, char end) {
 +  char *out = (char *) malloc(2 * strlen(str) + 4);
 +  char *o = out;
 +  size_t len;
 +
 +  *(o++) = '\"';
 +  for (; *str; str++) {
 +    if (*str == '\0') {
 +      break;
 +    } else if (*str == '\"') {
 +      *(o++) = '\"';
 +      *(o++) = '\"';
 +    } else {
 +      *(o++) = *str;
 +    }
 +  }
 +  *(o++) = '\"';
 +  *(o++) = end;
 +  *(o++) = '\0';
 +
 +  len = strlen(out);
 +  if (fwrite(out, len, 1, f) != 1) {
 +    perror("fwrite");
 +    exit(EXIT_FAILURE);
 +  }
 +
 +  free(out);
 +}
 +
 +static void unescape(char *str) {
 +  char *i = str, *o = str, tmp;
 +
 +  while (*i) {
 +    if (*i == '\\') {
 +      i++;
 +      switch (tmp = *i++) {
 +        case 's': *o++ = ';'; break;
 +        case 'e': *o++ = '='; break;
 +        case '\\': *o++ = '\\'; break;
 +        default: *o++ = tmp; break;
 +      }
 +    } else {
 +      *o++ = *i++;
 +    }
 +  }
 +}
 +
 +static int read_node_tags(char **tags, char **k, char **v) {
 +  if (!**tags) return 0;
 +  char *i = strchr(*tags, ';');
 +  if (!i) i = *tags + strlen(*tags);
 +  char *j = strchr(*tags, '=');
 +  *k = *tags;
 +  if (j && j < i) {
 +    *v = j + 1;
 +  } else {
 +    *v = i;
 +  }
 +  *tags = *i ? i + 1 : i;
 +  *i = '\0';
 +  if (j) *j = '\0';
 +
 +  unescape(*k);
 +  unescape(*v);
 +
 +  return 1;
 +}
 +
 +struct data {
 +  MYSQL *mysql;
 +  size_t version_size;
 +  uint16_t *version;
 +};
 +
 +static void proc_nodes(struct data *d, const char *tbl, FILE *out, FILE *out_tags, int hist) {
 +  MYSQL_RES *res;
 +  MYSQL_ROW row;
 +  char query[256];
 +
 +  snprintf(query, sizeof(query),  "SELECT id, latitude, longitude, "
 +      "user_id, visible, tags, timestamp, tile FROM %s", tbl);
 +  if (mysql_query(d->mysql, query))
 +    exit_mysql_err(d->mysql);
 +
 +  res = mysql_use_result(d->mysql);
 +  if (!res) exit_mysql_err(d->mysql);
 +
 +  while ((row = mysql_fetch_row(res))) {
 +    unsigned long id = strtoul(row[0], NULL, 10);
 +    uint32_t version;
 +
 +    if (id >= d->version_size) {
 +      fprintf(stderr, "preallocated nodes size exceeded");
 +      abort();
 +    }
 +
 +    if (hist) {
 +      version = ++(d->version[id]);
 +
 +      fprintf(out, "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%u\"\n",
 +        row[0], row[1], row[2], row[3], row[4], row[6], row[7], version);
 +    } else {
 +      /*fprintf(out, "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n",
 +      row[0], row[1], row[2], row[3], row[4], row[6], row[7]);*/
 +    }
 +
 +    char *tags_it = row[5], *k, *v;
 +    while (read_node_tags(&tags_it, &k, &v)) {
 +      if (hist) {
 +        fprintf(out_tags, "\"%s\",\"%u\",", row[0], version);
 +      } else {
 +        fprintf(out_tags, "\"%s\",", row[0]);
 +      }
 +
 +      write_csv_col(out_tags, k, ',');
 +      write_csv_col(out_tags, v, '\n');
 +    }
 +  }
 +  if (mysql_errno(d->mysql)) exit_mysql_err(d->mysql);
 +
 +  mysql_free_result(res);
 +}
 +
 +static size_t select_size(MYSQL *mysql, const char *q) {
 +  MYSQL_RES *res;
 +  MYSQL_ROW row;
 +  size_t ret;
 +
 +  if (mysql_query(mysql, q))
 +    exit_mysql_err(mysql);
 +
 +  res = mysql_store_result(mysql);
 +  if (!res) exit_mysql_err(mysql);
 +
 +  row = mysql_fetch_row(res);
 +  if (!row) exit_mysql_err(mysql);
 +
 +  if (row[0]) {
 +    ret = strtoul(row[0], NULL, 10);
 +  } else {
 +    ret = 0;
 +  }
 +
 +  mysql_free_result(res);
 +
 +  return ret;
 +}
 +
 +static MYSQL *connect_to_mysql(char **argv) {
 +  MYSQL *mysql = mysql_init(NULL);
 +  if (!mysql) exit_mysql_err(mysql);
 +
 +  if (!mysql_real_connect(mysql, argv[1], argv[2], argv[3], argv[4],
 +      argv[5][0] ? atoi(argv[5]) : 0, argv[6][0] ? argv[6] : NULL, 0))
 +    exit_mysql_err(mysql);
 +
 +  if (mysql_set_character_set(mysql, "utf8"))
 +    exit_mysql_err(mysql);
 +
 +  return mysql;
 +}
 +
 +static void open_file(FILE **f, char *fn) {
 +  *f = fopen(fn, "w+");
 +  if (!*f) {
 +    perror("fopen");
 +    exit(EXIT_FAILURE);
 +  }
 +}
 +
 +int main(int argc, char **argv) {
 +  size_t prefix_len;
 +  FILE *current_nodes, *current_node_tags, *nodes, *node_tags;
 +  char *tempfn;
 +  struct data data, *d = &data;
 +
 +  if (argc != 8) {
++    printf("Usage: 018_populate_node_tags_and_remove_helper host user passwd database port socket prefix\n");
 +    exit(EXIT_FAILURE);
 +  }
 +
 +  d->mysql = connect_to_mysql(argv);
 +
 +  d->version_size = 1 + select_size(d->mysql, "SELECT max(id) FROM current_nodes");
 +  d->version = (uint16_t *) malloc(sizeof(uint16_t) * d->version_size);
 +  if (!d->version) {
 +    perror("malloc");
 +    abort();
 +    exit(EXIT_FAILURE);
 +  }
 +  memset(d->version, 0, sizeof(uint16_t) * d->version_size);
 +
 +  prefix_len = strlen(argv[7]);
 +  tempfn = (char *) malloc(prefix_len + 32);
 +  strcpy(tempfn, argv[7]);
 +
 +  strcpy(tempfn + prefix_len, "current_nodes");
 +  open_file(&current_nodes, tempfn);
 +
 +  strcpy(tempfn + prefix_len, "current_node_tags");
 +  open_file(&current_node_tags, tempfn);
 +
 +  strcpy(tempfn + prefix_len, "nodes");
 +  open_file(&nodes, tempfn);
 +
 +  strcpy(tempfn + prefix_len, "node_tags");
 +  open_file(&node_tags, tempfn);
 +
 +  free(tempfn);
 +
 +  proc_nodes(d, "nodes", nodes, node_tags, 1);
 +  proc_nodes(d, "current_nodes", current_nodes, current_node_tags, 0);
 +
 +  free(d->version);
 +
 +  mysql_close(d->mysql);
 +
 +  fclose(current_nodes);
 +  fclose(current_node_tags);
 +  fclose(nodes);
 +  fclose(node_tags);
 +
 +  exit(EXIT_SUCCESS);
 +}
index d17da8fd549649eafdb09e019d779ca986643967,0000000000000000000000000000000000000000..d17da8fd549649eafdb09e019d779ca986643967
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,45 @@@
 +class MoveToInnodb < ActiveRecord::Migration
 +  @@conv_tables = ['nodes', 'ways', 'way_tags', 'way_nodes',
 +    'current_way_tags', 'relation_members',
 +    'relations', 'relation_tags', 'current_relation_tags']
 +
 +  @@ver_tbl = ['nodes', 'ways', 'relations']
 +
 +  def self.up
 +    execute 'DROP INDEX current_way_tags_v_idx ON current_way_tags'
 +    execute 'DROP INDEX current_relation_tags_v_idx ON current_relation_tags'
 +
 +    @@ver_tbl.each { |tbl|
 +      change_column tbl, "version", :bigint, :limit => 20, :null => false
 +    }
 +
 +    @@conv_tables.each { |tbl|
 +      execute "ALTER TABLE #{tbl} ENGINE = InnoDB"
 +    }
 +
 +    @@ver_tbl.each { |tbl|
 +      add_column "current_#{tbl}", "version", :bigint, :limit => 20, :null => false
 +      # As the initial version of all nodes, ways and relations is 0, we set the 
 +      # current version to something less so that we can update the version in 
 +      # batches of 10000
 +      tbl.classify.constantize.update_all("version=-1")
 +      while tbl.classify.constantize.count(:conditions => {:version => -1}) > 0
 +        tbl.classify.constantize.update_all("version=(SELECT max(version) FROM #{tbl} WHERE #{tbl}.id = current_#{tbl}.id)", {:version => -1}, :limit => 10000)
 +      end
 +     # execute "UPDATE current_#{tbl} SET version = " +
 +      #  "(SELECT max(version) FROM #{tbl} WHERE #{tbl}.id = current_#{tbl}.id)"
 +        # The above update causes a MySQL error:
 +        # -- add_column("current_nodes", "version", :bigint, {:null=>false, :limit=>20})
 +        # -> 1410.9152s
 +        # -- execute("UPDATE current_nodes SET version = (SELECT max(version) FROM nodes WHERE nodes.id = current_nodes.id)")
 +        # rake aborted!
 +        # Mysql::Error: The total number of locks exceeds the lock table size: UPDATE current_nodes SET version = (SELECT max(version) FROM nodes WHERE nodes.id = current_nodes.id)
 +
 +        # The above rails version will take longer, however will no run out of locks
 +    }
 +  end
 +
 +  def self.down
 +    raise IrreversibleMigration.new
 +  end
 +end
index 40f98be02b9eb3dd61cc0538612fff288d353492,0000000000000000000000000000000000000000..40f98be02b9eb3dd61cc0538612fff288d353492
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,50 @@@
 +class KeyConstraints < ActiveRecord::Migration
 +  def self.up
 +    # Primary keys
 +    add_primary_key :current_node_tags, [:id, :k]
 +    add_primary_key :current_way_tags, [:id, :k]
 +    add_primary_key :current_relation_tags, [:id, :k]
 +
 +    add_primary_key :node_tags, [:id, :version, :k]
 +    add_primary_key :way_tags, [:id, :version, :k]
 +    add_primary_key :relation_tags, [:id, :version, :k]
 +
 +    add_primary_key :nodes, [:id, :version]
 +
 +    # Remove indexes superseded by primary keys
 +    remove_index :current_way_tags, :name => :current_way_tags_id_idx
 +    remove_index :current_relation_tags, :name => :current_relation_tags_id_idx
 +
 +    remove_index :way_tags, :name => :way_tags_id_version_idx
 +    remove_index :relation_tags, :name => :relation_tags_id_version_idx
 +
 +    remove_index :nodes, :name => :nodes_uid_idx
 +
 +    # Foreign keys (between ways, way_tags, way_nodes, etc.)
 +    add_foreign_key :current_node_tags, [:id], :current_nodes
 +    add_foreign_key :node_tags, [:id, :version], :nodes
 +
 +    add_foreign_key :current_way_tags, [:id], :current_ways
 +    add_foreign_key :current_way_nodes, [:id], :current_ways
 +    add_foreign_key :way_tags, [:id, :version], :ways
 +    add_foreign_key :way_nodes, [:id, :version], :ways
 +
 +    add_foreign_key :current_relation_tags, [:id], :current_relations
 +    add_foreign_key :current_relation_members, [:id], :current_relations
 +    add_foreign_key :relation_tags, [:id, :version], :relations
 +    add_foreign_key :relation_members, [:id, :version], :relations
 +
 +    # Foreign keys (between different types of primitives)
 +    add_foreign_key :current_way_nodes, [:node_id], :current_nodes, [:id]
 +
 +    # FIXME: We don't have foreign keys for relation members since the id
 +    # might point to a different table depending on the `type' column.
 +    # We'd probably need different current_relation_member_nodes,
 +    # current_relation_member_ways and current_relation_member_relations
 +    # tables for this to work cleanly.
 +  end
 +
 +  def self.down
 +    raise IrreversibleMigration.new
 +  end
 +end
index 772a5f20daf051aee38f3cb6e3a3c69ca96846ba,0000000000000000000000000000000000000000..772a5f20daf051aee38f3cb6e3a3c69ca96846ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,46 -1,0 +1,46 @@@
 +class AddChangesets < ActiveRecord::Migration
 +  @@conv_user_tables = ['current_nodes',
 +  'current_relations', 'current_ways', 'nodes', 'relations', 'ways' ]
 +  
 +  def self.up
 +    create_table "changesets", innodb_table do |t|
 +      t.column "user_id",        :bigint,   :limit => 20, :null => false
 +      t.column "created_at",     :datetime,               :null => false
 +      t.column "open",           :boolean,                :null => false, :default => true
 +      t.column "min_lat",        :integer,                :null => true
 +      t.column "max_lat",        :integer,                :null => true
 +      t.column "min_lon",        :integer,                :null => true
 +      t.column "max_lon",        :integer,                :null => true
 +    end
 +    add_column :changesets, :id, :bigint_pk
 +
 +    create_table "changeset_tags", innodb_table do |t|
 +      t.column "id", :bigint, :limit => 64, :null => false
 +      t.column "k",  :string, :default => "", :null => false
 +      t.column "v",  :string, :default => "", :null => false
 +    end
 +
 +    add_index "changeset_tags", ["id"], :name => "changeset_tags_id_idx"
 +    
 +    #
 +    # Initially we will have one changeset for every user containing 
 +    # all edits up to the API change,  
 +    # all the changesets will have the id of the user that made them.
 +    # We need to generate a changeset for each user in the database
 +    execute "INSERT INTO changesets (id, user_id, created_at, open)" + 
 +      "SELECT id, id, creation_time, 0 from users;"
 +
 +    @@conv_user_tables.each { |tbl|
 +      rename_column tbl, :user_id, :changeset_id
 +      #foreign keys too
 +      add_foreign_key tbl, [:changeset_id], :changesets, [:id]
 +    }
 +  end
 +
 +  def self.down
 +    # It's not easy to generate the user ids from the changesets
 +    raise IrreversibleMigration.new
 +    #drop_table "changesets"
 +    #drop_table "changeset_tags"
 +  end
 +end
index c2ddf9c391fb7cb461a3c3f4aed48b933638989e,c80ed2242c8147db90177925af3db63eacee971f..fcf34336f7dbb23d55aa1eb151e8dea967967252
@@@ -13,8 -13,6 +13,8 @@@ var nonamekeys = 
  };
  
  OpenLayers._getScriptLocation = function () {
 +  // Should really have this file as an erb, so that this can return 
 +  // the real rails root
     return "/openlayers/";
  }
  
@@@ -32,7 -30,8 +32,8 @@@ function createMap(divName, options) 
        ],
        units: "m",
        maxResolution: 156543.0339,
-       numZoomLevels: 20
+       numZoomLevels: 20,
+       displayProjection: new OpenLayers.Projection("EPSG:4326")
     });
  
     var mapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik", {
@@@ -133,6 -132,8 +134,8 @@@ function getMapCenter(center, zoom) 
  }
  
  function setMapCenter(center, zoom) {
+    var numzoom = map.getNumZoomLevels();
+    if (zoom >= numzoom) zoom = numzoom - 1;
     map.setCenter(center.clone().transform(epsg4326, map.getProjectionObject()), zoom);
  }