Merge 18123:18249 from trunk.

This commit is contained in:
Tom Hughes 2009-10-21 23:37:05 +00:00
commit 0166abe88a
63 changed files with 4951 additions and 419 deletions

View file

@ -5,8 +5,8 @@
#
# Helper functions are in /lib/potlatch.rb
#
# Author:: editions Systeme D / Richard Fairhurst 2004-2008
# Licence:: public domain.
# Author:: editions Systeme D / Richard Fairhurst 2004-2008
# Licence:: public domain.
#
# == General structure
#
@ -24,8 +24,8 @@
# == Debugging
#
# Any method that returns a status code (0 for ok) can also send:
# return(-1,"message") <-- just puts up a dialogue
# return(-2,"message") <-- also asks the user to e-mail me
# return(-1,"message") <-- just puts up a dialogue
# return(-2,"message") <-- also asks the user to e-mail me
# return(-3,["type",v],id) <-- version conflict
# return(-4,"type",id) <-- object not found
# -5 indicates the method wasn't called (due to a previous error)
@ -52,45 +52,47 @@ class AmfController < ApplicationController
def amf_read
if request.post?
req=StringIO.new(request.raw_post+0.chr)# Get POST data as request
# (cf http://www.ruby-forum.com/topic/122163)
req.read(2) # Skip version indicator and client ID
results={} # Results of each body
# (cf http://www.ruby-forum.com/topic/122163)
req.read(2) # Skip version indicator and client ID
# Parse request
headers=AMF.getint(req) # Read number of headers
headers.times do # Read each header
name=AMF.getstring(req) # |
req.getc # | skip boolean
value=AMF.getvalue(req) # |
header["name"]=value # |
headers=AMF.getint(req) # Read number of headers
headers.times do # Read each header
name=AMF.getstring(req) # |
req.getc # | skip boolean
value=AMF.getvalue(req) # |
header["name"]=value # |
end
bodies=AMF.getint(req) # Read number of bodies
bodies.times do # Read each body
message=AMF.getstring(req) # | get message name
index=AMF.getstring(req) # | get index in response sequence
bytes=AMF.getlong(req) # | get total size in bytes
args=AMF.getvalue(req) # | get response (probably an array)
logger.info("Executing AMF #{message}(#{args.join(',')}):#{index}")
bodies=AMF.getint(req) # Read number of bodies
render :content_type => "application/x-amf", :text => proc { |response, output|
a,b=bodies.divmod(256)
output.write 0.chr+0.chr+0.chr+0.chr+a.chr+b.chr
bodies.times do # Read each body
message=AMF.getstring(req) # | get message name
index=AMF.getstring(req) # | get index in response sequence
bytes=AMF.getlong(req) # | get total size in bytes
args=AMF.getvalue(req) # | get response (probably an array)
result=''
logger.info("Executing AMF #{message}(#{args.join(',')}):#{index}")
case message
when 'getpresets'; results[index]=AMF.putdata(index,getpresets(*args))
when 'whichways'; results[index]=AMF.putdata(index,whichways(*args))
when 'whichways_deleted'; results[index]=AMF.putdata(index,whichways_deleted(*args))
when 'getway'; results[index]=AMF.putdata(index,getway(args[0].to_i))
when 'getrelation'; results[index]=AMF.putdata(index,getrelation(args[0].to_i))
when 'getway_old'; results[index]=AMF.putdata(index,getway_old(args[0].to_i,args[1]))
when 'getway_history'; results[index]=AMF.putdata(index,getway_history(args[0].to_i))
when 'getnode_history'; results[index]=AMF.putdata(index,getnode_history(args[0].to_i))
when 'findgpx'; results[index]=AMF.putdata(index,findgpx(*args))
when 'findrelations'; results[index]=AMF.putdata(index,findrelations(*args))
when 'getpoi'; results[index]=AMF.putdata(index,getpoi(*args))
case message
when 'getpresets'; result=AMF.putdata(index,getpresets(*args))
when 'whichways'; result=AMF.putdata(index,whichways(*args))
when 'whichways_deleted'; result=AMF.putdata(index,whichways_deleted(*args))
when 'getway'; result=AMF.putdata(index,getway(args[0].to_i))
when 'getrelation'; result=AMF.putdata(index,getrelation(args[0].to_i))
when 'getway_old'; result=AMF.putdata(index,getway_old(args[0].to_i,args[1]))
when 'getway_history'; result=AMF.putdata(index,getway_history(args[0].to_i))
when 'getnode_history'; result=AMF.putdata(index,getnode_history(args[0].to_i))
when 'findgpx'; result=AMF.putdata(index,findgpx(*args))
when 'findrelations'; result=AMF.putdata(index,findrelations(*args))
when 'getpoi'; result=AMF.putdata(index,getpoi(*args))
end
output.write(result)
end
end
logger.info("Encoding AMF results")
sendresponse(results)
}
else
render :nothing => true, :status => :method_not_allowed
end
@ -100,48 +102,51 @@ class AmfController < ApplicationController
if request.post?
req=StringIO.new(request.raw_post+0.chr)
req.read(2)
results={}
renumberednodes={} # Shared across repeated putways
renumberedways={} # Shared across repeated putways
renumberednodes={} # Shared across repeated putways
renumberedways={} # Shared across repeated putways
headers=AMF.getint(req) # Read number of headers
headers.times do # Read each header
name=AMF.getstring(req) # |
req.getc # | skip boolean
value=AMF.getvalue(req) # |
header["name"]=value # |
headers=AMF.getint(req) # Read number of headers
headers.times do # Read each header
name=AMF.getstring(req) # |
req.getc # | skip boolean
value=AMF.getvalue(req) # |
header["name"]=value # |
end
bodies=AMF.getint(req) # Read number of bodies
bodies.times do # Read each body
message=AMF.getstring(req) # | get message name
index=AMF.getstring(req) # | get index in response sequence
bytes=AMF.getlong(req) # | get total size in bytes
args=AMF.getvalue(req) # | get response (probably an array)
err=false # Abort batch on error
bodies=AMF.getint(req) # Read number of bodies
render :content_type => "application/x-amf", :text => proc { |response, output|
a,b=bodies.divmod(256)
output.write 0.chr+0.chr+0.chr+0.chr+a.chr+b.chr
bodies.times do # Read each body
message=AMF.getstring(req) # | get message name
index=AMF.getstring(req) # | get index in response sequence
bytes=AMF.getlong(req) # | get total size in bytes
args=AMF.getvalue(req) # | get response (probably an array)
err=false # Abort batch on error
logger.info("Executing AMF #{message}:#{index}")
if err
results[index]=[-5,nil]
else
case message
when 'putway'; orn=renumberednodes.dup
r=putway(renumberednodes,*args)
r[4]=renumberednodes.reject { |k,v| orn.has_key?(k) }
if r[2] != r[3] then renumberedways[r[2]] = r[3] end
results[index]=AMF.putdata(index,r)
when 'putrelation'; results[index]=AMF.putdata(index,putrelation(renumberednodes, renumberedways, *args))
when 'deleteway'; results[index]=AMF.putdata(index,deleteway(*args))
when 'putpoi'; r=putpoi(*args)
if r[2] != r[3] then renumberednodes[r[2]] = r[3] end
results[index]=AMF.putdata(index,r)
when 'startchangeset'; results[index]=AMF.putdata(index,startchangeset(*args))
end
if results[index][0]==-3 then err=true end # If a conflict is detected, don't execute any more writes
logger.info("Executing AMF #{message}:#{index}")
result=''
if err
result=[-5,nil]
else
case message
when 'putway'; orn=renumberednodes.dup
r=putway(renumberednodes,*args)
r[4]=renumberednodes.reject { |k,v| orn.has_key?(k) }
if r[2] != r[3] then renumberedways[r[2]] = r[3] end
result=AMF.putdata(index,r)
when 'putrelation'; result=AMF.putdata(index,putrelation(renumberednodes, renumberedways, *args))
when 'deleteway'; result=AMF.putdata(index,deleteway(*args))
when 'putpoi'; r=putpoi(*args)
if r[2] != r[3] then renumberednodes[r[2]] = r[3] end
result=AMF.putdata(index,r)
when 'startchangeset'; result=AMF.putdata(index,startchangeset(*args))
end
if result[0]==-3 then err=true end # If a conflict is detected, don't execute any more writes
end
output.write(result)
end
end
logger.info("Encoding AMF results")
sendresponse(results)
}
else
render :nothing => true, :status => :method_not_allowed
end
@ -193,7 +198,7 @@ class AmfController < ApplicationController
cs.save_with_tags!
end
end
# open a new changeset
if opennew!=0
cs = Changeset.new
@ -232,6 +237,12 @@ class AmfController < ApplicationController
help = localised["help_html"]
localised.delete("help_html")
# Populate icon names
POTLATCH_PRESETS[10].each { |id|
POTLATCH_PRESETS[11][id] = localised["preset_icon_#{id}"]
localised.delete("preset_icon_#{id}")
}
return POTLATCH_PRESETS+[localised,help]
end
@ -243,7 +254,7 @@ class AmfController < ApplicationController
en = YAML::load(File.open("#{RAILS_ROOT}/config/potlatch/locales/en.yml"))["en"]
if lang == 'en'
return [real_lang, en]
return [loaded_lang, en]
else
# Use English as a fallback
begin
@ -633,7 +644,7 @@ class AmfController < ApplicationController
def putway(renumberednodes, usertoken, changeset_id, wayversion, originalway, pointlist, attributes, nodes, deletednodes) #:doc:
amf_handle_error("'putway' #{originalway}" ,'way',originalway) do
# -- Initialise
user = getuser(usertoken)
if !user then return -1,"You are not logged in, so the way could not be saved." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
@ -644,7 +655,7 @@ class AmfController < ApplicationController
originalway = originalway.to_i
pointlist.collect! {|a| a.to_i }
way=nil # this is returned, so scope it outside the transaction
way=nil # this is returned, so scope it outside the transaction
nodeversions = {}
Way.transaction do
@ -697,7 +708,7 @@ class AmfController < ApplicationController
new_way.version = wayversion
if originalway <= 0
new_way.create_with_history(user)
way=new_way # so we can get way.id and way.version
way=new_way # so we can get way.id and way.version
else
way = Way.find(originalway)
if way.tags!=attributes or way.nds!=pointlist or !way.visible?
@ -881,21 +892,6 @@ class AmfController < ApplicationController
return user
end
# Send AMF response
def sendresponse(results)
a,b=results.length.divmod(256)
render :content_type => "application/x-amf", :text => proc { |response, output|
# ** move amf writing loop into here -
# basically we read the messages in first (into an array of some sort),
# then iterate through that array within here, and do all the AMF writing
output.write 0.chr+0.chr+0.chr+0.chr+a.chr+b.chr
results.each do |k,v|
output.write(v)
end
}
end
def getlocales
Dir.glob("#{RAILS_ROOT}/config/potlatch/locales/*").collect { |f| File.basename(f, ".yml") }
end
@ -940,16 +936,16 @@ class AmfController < ApplicationController
EOF
return ActiveRecord::Base.connection.select_all(sql).collect { |a| [a['wayid'].to_i,a['version'].to_i] }
end
def sql_find_pois_in_area(xmin,ymin,xmax,ymax)
pois=[]
sql=<<-EOF
SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version
FROM current_nodes
SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version
FROM current_nodes
LEFT OUTER JOIN current_way_nodes cwn ON cwn.node_id=current_nodes.id
WHERE current_nodes.visible=TRUE
AND cwn.id IS NULL
AND #{OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes.")}
WHERE current_nodes.visible=TRUE
AND cwn.id IS NULL
AND #{OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes.")}
EOF
ActiveRecord::Base.connection.select_all(sql).each do |row|
poitags={}
@ -960,7 +956,7 @@ class AmfController < ApplicationController
end
pois
end
def sql_find_relations_in_area_and_ways(xmin,ymin,xmax,ymax,way_ids)
# ** It would be more Potlatchy to get relations for nodes within ways
# during 'getway', not here
@ -983,17 +979,17 @@ class AmfController < ApplicationController
end
ActiveRecord::Base.connection.select_all(sql).collect { |a| [a['relid'].to_i,a['version'].to_i] }
end
def sql_get_nodes_in_way(wayid)
points=[]
sql=<<-EOF
SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lon,current_nodes.id,current_nodes.version
FROM current_way_nodes,current_nodes
WHERE current_way_nodes.id=#{wayid.to_i}
AND current_way_nodes.node_id=current_nodes.id
AND current_nodes.visible=TRUE
AND current_way_nodes.node_id=current_nodes.id
AND current_nodes.visible=TRUE
ORDER BY sequence_id
EOF
EOF
ActiveRecord::Base.connection.select_all(sql).each do |row|
nodetags={}
ActiveRecord::Base.connection.select_all("SELECT k,v FROM current_node_tags WHERE id=#{row['id']}").each do |n|
@ -1004,7 +1000,7 @@ class AmfController < ApplicationController
end
points
end
def sql_get_tags_in_way(wayid)
tags={}
ActiveRecord::Base.connection.select_all("SELECT k,v FROM current_way_tags WHERE id=#{wayid.to_i}").each do |row|

View file

@ -20,10 +20,12 @@ class GeocoderController < ApplicationController
elsif @query.match(/^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i)
@sources.push "uk_postcode"
@sources.push "osm_namefinder"
@sources.push "osm_twain" if APP_CONFIG['twain_enabled']
elsif @query.match(/^[A-Z]\d[A-Z]\s*\d[A-Z]\d$/i)
@sources.push "ca_postcode"
else
@sources.push "osm_namefinder"
@sources.push "osm_twain" if APP_CONFIG['twain_enabled']
@sources.push "geonames"
end
@ -213,6 +215,44 @@ class GeocoderController < ApplicationController
render :action => "error"
end
def search_osm_twain
# get query parameters
query = params[:query]
# create result array
@results = Array.new
# ask OSM namefinder
response = fetch_xml("http://katie.openstreetmap.org/~twain/?format=xml&polygon=true&q=#{escape_query(query)}")
# parse the response
response.elements.each("searchresults/place") do |place|
lat = place.attributes["lat"].to_s
lon = place.attributes["lon"].to_s
zoom = place.attributes["zoom"].to_s
klass = place.attributes["class"].to_s
type = place.attributes["type"].to_s
name = place.attributes["display_name"].to_s
min_lat,max_lat,min_lon,max_lon = place.attributes["boundingbox"].to_s.split(",")
if klass == "highway"
prefix = t 'geocoder.search_osm_twain.prefix_highway', :type => type.capitalize
else
prefix = t 'geocoder.search_osm_twain.prefix_other', :type => type.capitalize
end
@results.push({:lat => lat, :lon => lon, :zoom => zoom,
:min_lat => min_lat, :max_lat => max_lat,
:min_lon => min_lon, :max_lon => max_lon,
:prefix => prefix, :name => name})
end
render :action => "results"
rescue Exception => ex
@error = "Error contacting katie.openstreetmap.org: #{ex.to_s}"
render :action => "error"
end
def search_geonames
# get query parameters
query = params[:query]
@ -240,7 +280,7 @@ class GeocoderController < ApplicationController
@error = "Error contacting ws.geonames.org: #{ex.to_s}"
render :action => "error"
end
def description
@sources = Array.new

View file

@ -6,7 +6,13 @@ module GeocoderHelper
html = ""
html << result[:prefix] if result[:prefix]
html << " " if result[:prefix] and result[:name]
html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, #{result[:zoom]})", html_options) if result[:name]
if result[:min_lon] and result[:min_lat] and result[:max_lon] and result[:max_lat]
html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, #{result[:zoom]}, #{result[:min_lon]}, #{result[:min_lat]}, #{result[:max_lon]}, #{result[:max_lat]})", html_options) if result[:name]
else
html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, #{result[:zoom]})", html_options) if result[:name]
end
html << result[:suffix] if result[:suffix]
return html
end

View file

@ -115,7 +115,7 @@
<div id="left_menu" class="left_menu">
<a href="<%= t 'layouts.help_wiki_url' %>" title="<%= t 'layouts.help_wiki_tooltip' %>"><%= t 'layouts.help_wiki' %></a><br />
<a href="http://www.opengeodata.org" title="<%= t 'layouts.news_blog_tooltip' %>"><%= t 'layouts.news_blog' %></a><br />
<a href="http://blog.openstreetmap.org/" title="<%= t 'layouts.news_blog_tooltip' %>"><%= t 'layouts.news_blog' %></a><br />
<a href="<%= t 'layouts.shop_url' %>" title="<%= t 'layouts.shop_tooltip' %>"><%= t 'layouts.shop' %></a><br />
<%= yield :left_menu %>
</div>

View file

@ -20,6 +20,11 @@
<%= t'notifier.signup_confirm_plain.the_wiki_url' %>
<%= t'notifier.signup_confirm_plain.blog_and_twitter' %>
http://blog.openstreepmap.org/
http://twitter.com/openstreetmap
<%= t'notifier.signup_confirm_plain.opengeodata' %>
http://www.opengeodata.org/

View file

@ -27,7 +27,8 @@
<div id="search_field">
<% form_remote_tag(:loading => "startSearch()",
:complete => "endSearch()",
:url => { :controller => :geocoder, :action => :search }) do %>
:url => { :controller => :geocoder, :action => :search },
:html => { :method => "get", :action => url_for(:action => "index") }) do %>
<%= text_field_tag :query, h(params[:query]) %>
<%= submit_tag t('site.search.submit_text') %>
<% end %>

View file

@ -191,10 +191,16 @@ end
return getMapCenter();
}
function setPosition(lat, lon, zoom) {
function setPosition(lat, lon, zoom, min_lon, min_lat, max_lon, max_lat) {
var centre = new OpenLayers.LonLat(lon, lat);
setMapCenter(centre, zoom);
if (min_lon && min_lat && max_lon && max_lat) {
var bbox = new OpenLayers.Bounds(min_lon, min_lat, max_lon, max_lat);
setMapExtent(bbox);
} else {
setMapCenter(centre, zoom);
}
if (marker)
removeMarkerFromMap(marker);

View file

@ -1,9 +1,13 @@
<h1><%= t 'user.lost_password.heading' %></h1><br>
<h1><%= t 'user.lost_password.heading' %></h1>
<p><%= t 'user.lost_password.help_text' %></p>
<% form_tag :action => 'lost_password' do %>
<table>
<tr><td><%= t 'user.lost_password.email address' %></td><td><%= text_field('user', 'email', {:size => 50, :maxlength => 255} ) %></td></tr>
<tr>
<td class="fieldName"><%= t 'user.lost_password.email address' %></td>
<td><%= text_field('user', 'email', {:size => 50, :maxlength => 255, :tabindex => 1} ) %></td>
</tr>
<tr><td></td><td align="right"><input type="submit" value="<%= t'user.lost_password.new password button' %>" tabindex="2"></td></tr>
</table>
<br>
<input type="submit" value="<%= t 'user.lost_password.new password button' %>">
<% end %>

View file

@ -26,6 +26,7 @@
<tr><td></td><td><span class="minorNote"><%= t 'user.new.not displayed publicly' %></span></td></tr>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
<tr><td class="fieldName"><%= t 'user.new.display name' %></td><td><%= text_field('user', 'display_name',{:size => 30, :maxlength => 255, :tabindex => 3}) %></td></tr>
<tr><td></td><td><span class="minorNote"><%= t 'user.new.display name description' %></span></td></tr>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
<tr><td class="fieldName"><%= t 'user.new.password' %></td><td><%= password_field('user', 'pass_crypt',{:size => 30, :maxlength => 255, :tabindex => 4}) %></td></tr>
<tr><td class="fieldName"><%= t 'user.new.confirm password' %></td><td><%= password_field('user', 'pass_crypt_confirmation',{:size => 30, :maxlength => 255, :tabindex => 5}) %></td></tr>