Merge api06 branch to trunk.

This commit is contained in:
Tom Hughes 2009-04-20 09:12:03 +00:00
commit fd6f00b069
196 changed files with 10115 additions and 1794 deletions

File diff suppressed because it is too large Load diff

View file

@ -11,12 +11,13 @@ class ApiController < ApplicationController
@@count = COUNT
# The maximum area you're allowed to request, in square degrees
MAX_REQUEST_AREA = 0.25
MAX_REQUEST_AREA = APP_CONFIG['max_request_area']
# Number of GPS trace/trackpoints returned per-page
TRACEPOINTS_PER_PAGE = 5000
TRACEPOINTS_PER_PAGE = APP_CONFIG['tracepoints_per_page']
# Get an XML response containing a list of tracepoints that have been uploaded
# within the specified bounding box, and in the specified page.
def trackpoints
@@count+=1
#retrieve the page number
@ -84,6 +85,15 @@ class ApiController < ApplicationController
render :text => doc.to_s, :content_type => "text/xml"
end
# This is probably the most common call of all. It is used for getting the
# OSM data for a specified bounding box, usually for editing. First the
# bounding box (bbox) is checked to make sure that it is sane. All nodes
# are searched, then all the ways that reference those nodes are found.
# All Nodes that are referenced by those ways are fetched and added to the list
# of nodes.
# Then all the relations that reference the already found nodes and ways are
# fetched. All the nodes and ways that are referenced by those ways are then
# fetched. Finally all the xml is returned.
def map
GC.start
@@count+=1
@ -109,18 +119,19 @@ class ApiController < ApplicationController
return
end
@nodes = Node.find_by_area(min_lat, min_lon, max_lat, max_lon, :conditions => "visible = 1", :limit => APP_CONFIG['max_number_of_nodes']+1)
# FIXME um why is this area using a different order for the lat/lon from above???
@nodes = Node.find_by_area(min_lat, min_lon, max_lat, max_lon, :conditions => {:visible => true}, :limit => APP_CONFIG['max_number_of_nodes']+1)
# get all the nodes, by tag not yet working, waiting for change from NickB
# need to be @nodes (instance var) so tests in /spec can be performed
#@nodes = Node.search(bbox, params[:tag])
node_ids = @nodes.collect(&:id)
if node_ids.length > APP_CONFIG['max_number_of_nodes']
report_error("You requested too many nodes (limit is 50,000). Either request a smaller area, or use planet.osm")
report_error("You requested too many nodes (limit is #{APP_CONFIG['max_number_of_nodes']}). Either request a smaller area, or use planet.osm")
return
end
if node_ids.length == 0
render :text => "<osm version='0.5'></osm>", :content_type => "text/xml"
render :text => "<osm version='#{API_VERSION}' generator='#{GENERATOR}'></osm>", :content_type => "text/xml"
return
end
@ -176,15 +187,15 @@ class ApiController < ApplicationController
end
end
relations = Relation.find_for_nodes(visible_nodes.keys, :conditions => "visible = 1") +
Relation.find_for_ways(way_ids, :conditions => "visible = 1")
relations = Relation.find_for_nodes(visible_nodes.keys, :conditions => {:visible => true}) +
Relation.find_for_ways(way_ids, :conditions => {:visible => true})
# we do not normally return the "other" partners referenced by an relation,
# e.g. if we return a way A that is referenced by relation X, and there's
# another way B also referenced, that is not returned. But we do make
# an exception for cases where an relation references another *relation*;
# in that case we return that as well (but we don't go recursive here)
relations += Relation.find_for_relations(relations.collect { |r| r.id }, :conditions => "visible = 1")
relations += Relation.find_for_relations(relations.collect { |r| r.id }, :conditions => {:visible => true})
# this "uniq" may be slightly inefficient; it may be better to first collect and output
# all node-related relations, then find the *not yet covered* way-related ones etc.
@ -204,6 +215,8 @@ class ApiController < ApplicationController
end
end
# Get a list of the tiles that have changed within a specified time
# period
def changes
zoom = (params[:zoom] || '12').to_i
@ -212,12 +225,12 @@ class ApiController < ApplicationController
endtime = Time.parse(params[:end])
else
hours = (params[:hours] || '1').to_i.hours
endtime = Time.now
endtime = Time.now.getutc
starttime = endtime - hours
end
if zoom >= 1 and zoom <= 16 and
endtime >= starttime and endtime - starttime <= 24.hours
endtime > starttime and endtime - starttime <= 24.hours
mask = (1 << zoom) - 1
tiles = Node.count(:conditions => ["timestamp BETWEEN ? AND ?", starttime, endtime],
@ -245,21 +258,32 @@ class ApiController < ApplicationController
render :text => doc.to_s, :content_type => "text/xml"
else
render :nothing => true, :status => :bad_request
render :text => "Requested zoom is invalid, or the supplied start is after the end time, or the start duration is more than 24 hours", :status => :bad_request
end
end
# External apps that use the api are able to query the api to find out some
# parameters of the API. It currently returns:
# * minimum and maximum API versions that can be used.
# * maximum area that can be requested in a bbox request in square degrees
# * number of tracepoints that are returned in each tracepoints page
def capabilities
doc = OSM::API.new.get_xml_doc
api = XML::Node.new 'api'
version = XML::Node.new 'version'
version['minimum'] = '0.5';
version['maximum'] = '0.5';
version['minimum'] = "#{API_VERSION}";
version['maximum'] = "#{API_VERSION}";
api << version
area = XML::Node.new 'area'
area['maximum'] = MAX_REQUEST_AREA.to_s;
api << area
tracepoints = XML::Node.new 'tracepoints'
tracepoints['per_page'] = APP_CONFIG['tracepoints_per_page'].to_s
api << tracepoints
waynodes = XML::Node.new 'waynodes'
waynodes['maximum'] = APP_CONFIG['max_number_of_way_nodes'].to_s
api << waynodes
doc.root << api

View file

@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base
def authorize_web
if session[:user]
@user = User.find(session[:user], :conditions => "visible = 1")
@user = User.find(session[:user], :conditions => {:visible => true})
elsif session[:token]
@user = User.authenticate(:token => session[:token])
session[:user] = @user.id
@ -22,7 +22,11 @@ class ApplicationController < ActionController::Base
redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri unless @user
end
def authorize(realm='Web Password', errormessage="Couldn't authenticate you")
##
# sets up the @user object for use by other methods. this is mostly called
# from the authorize method, but can be called elsewhere if authorisation
# is optional.
def setup_user_auth
username, passwd = get_auth_data # parse from headers
# authenticate per-scheme
if username.nil?
@ -32,6 +36,11 @@ class ApplicationController < ActionController::Base
else
@user = User.authenticate(:username => username, :password => passwd) # basic auth
end
end
def authorize(realm='Web Password', errormessage="Couldn't authenticate you")
# make the @user object from any auth sources we have
setup_user_auth
# handle authenticate pass/fail
unless @user
@ -73,13 +82,21 @@ class ApplicationController < ActionController::Base
end
end
def require_public_data
unless @user.data_public?
response.headers['Error'] = "You must make your edits public to upload new data"
render :nothing => true, :status => :forbidden
return false
end
end
# Report and error to the user
# (If anyone ever fixes Rails so it can set a http status "reason phrase",
# rather than only a status code and having the web engine make up a
# phrase from that, we can also put the error message into the status
# message. For now, rails won't let us)
def report_error(message)
render :nothing => true, :status => :bad_request
render :text => message, :status => :bad_request
# Todo: some sort of escaping of problem characters in the message
response.headers['Error'] = message
end
@ -90,6 +107,8 @@ private
def get_auth_data
if request.env.has_key? 'X-HTTP_AUTHORIZATION' # where mod_rewrite might have put it
authdata = request.env['X-HTTP_AUTHORIZATION'].to_s.split
elsif request.env.has_key? 'REDIRECT_X_HTTP_AUTHORIZATION' # mod_fcgi
authdata = request.env['REDIRECT_X_HTTP_AUTHORIZATION'].to_s.split
elsif request.env.has_key? 'HTTP_AUTHORIZATION' # regular location
authdata = request.env['HTTP_AUTHORIZATION'].to_s.split
end

View file

@ -7,103 +7,109 @@ class BrowseController < ApplicationController
def start
end
def index
@nodes = Node.find(:all, :order => "timestamp DESC", :limit=> 20)
end
def relation
begin
@relation = Relation.find(params[:id])
@name = @relation.tags['name'].to_s
if @name.length == 0:
@name = "#" + @relation.id.to_s
end
@title = 'Relation | ' + (@name)
@next = Relation.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @relation.id }] )
@prev = Relation.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @relation.id }] )
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@relation = Relation.find(params[:id])
@name = @relation.tags['name'].to_s
if @name.length == 0:
@name = "#" + @relation.id.to_s
end
@title = 'Relation | ' + (@name)
@next = Relation.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @relation.id }] )
@prev = Relation.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @relation.id }] )
rescue ActiveRecord::RecordNotFound
@type = "relation"
render :action => "not_found", :status => :not_found
end
def relation_history
begin
@relation = Relation.find(params[:id])
@relation = Relation.find(params[:id])
@name = @relation.tags['name'].to_s
if @name.length == 0:
@name = "#" + @relation.id.to_s
end
@title = 'Relation History | ' + (@name)
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@name = @relation.tags['name'].to_s
if @name.length == 0:
@name = "#" + @relation.id.to_s
end
@title = 'Relation History | ' + (@name)
rescue ActiveRecord::RecordNotFound
@type = "relation"
render :action => "not_found", :status => :not_found
end
def way
begin
@way = Way.find(params[:id])
@way = Way.find(params[:id])
@name = @way.tags['name'].to_s
if @name.length == 0:
@name = "#" + @way.id.to_s
end
@title = 'Way | ' + (@name)
@next = Way.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @way.id }] )
@prev = Way.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @way.id }] )
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@name = @way.tags['name'].to_s
if @name.length == 0:
@name = "#" + @way.id.to_s
end
@title = 'Way | ' + (@name)
@next = Way.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @way.id }] )
@prev = Way.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @way.id }] )
rescue ActiveRecord::RecordNotFound
@type = "way"
render :action => "not_found", :status => :not_found
end
def way_history
begin
@way = Way.find(params[:id])
@way = Way.find(params[:id])
@name = @way.tags['name'].to_s
if @name.length == 0:
@name = "#" + @way.id.to_s
end
@title = 'Way History | ' + (@name)
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@name = @way.tags['name'].to_s
if @name.length == 0:
@name = "#" + @way.id.to_s
end
@title = 'Way History | ' + (@name)
rescue ActiveRecord::RecordNotFound
@type = "way"
render :action => "not_found", :status => :not_found
end
def node
begin
@node = Node.find(params[:id])
@node = Node.find(params[:id])
@name = @node.tags_as_hash['name'].to_s
if @name.length == 0:
@name = "#" + @node.id.to_s
end
@title = 'Node | ' + (@name)
@next = Node.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @node.id }] )
@prev = Node.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @node.id }] )
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@name = @node.tags_as_hash['name'].to_s
if @name.length == 0:
@name = "#" + @node.id.to_s
end
@title = 'Node | ' + (@name)
@next = Node.find(:first, :order => "id ASC", :conditions => [ "visible = true AND id > :id", { :id => @node.id }] )
@prev = Node.find(:first, :order => "id DESC", :conditions => [ "visible = true AND id < :id", { :id => @node.id }] )
rescue ActiveRecord::RecordNotFound
@type = "node"
render :action => "not_found", :status => :not_found
end
def node_history
begin
@node = Node.find(params[:id])
@node = Node.find(params[:id])
@name = @node.tags_as_hash['name'].to_s
if @name.length == 0:
@name = "#" + @node.id.to_s
end
@title = 'Node History | ' + (@name)
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
@name = @node.tags_as_hash['name'].to_s
if @name.length == 0:
@name = "#" + @node.id.to_s
end
@title = 'Node History | ' + (@name)
rescue ActiveRecord::RecordNotFound
@type = "way"
render :action => "not_found", :status => :not_found
end
def changeset
@changeset = Changeset.find(params[:id])
@node_pages, @nodes = paginate(:old_nodes, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'node_page')
@way_pages, @ways = paginate(:old_ways, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'way_page')
@relation_pages, @relations = paginate(:old_relations, :conditions => {:changeset_id => @changeset.id}, :per_page => 20, :parameter => 'relation_page')
@title = "Changeset | #{@changeset.id}"
@next = Changeset.find(:first, :order => "id ASC", :conditions => [ "id > :id", { :id => @changeset.id }] )
@prev = Changeset.find(:first, :order => "id DESC", :conditions => [ "id < :id", { :id => @changeset.id }] )
rescue ActiveRecord::RecordNotFound
@type = "changeset"
render :action => "not_found", :status => :not_found
end
end

View file

@ -0,0 +1,485 @@
# The ChangesetController is the RESTful interface to Changeset objects
class ChangesetController < ApplicationController
layout 'site'
require 'xml/libxml'
session :off, :except => [:list, :list_user, :list_bbox]
before_filter :authorize_web, :only => [:list, :list_user, :list_bbox]
before_filter :authorize, :only => [:create, :update, :delete, :upload, :include, :close]
before_filter :require_public_data, :only => [:create, :update, :delete, :upload, :include, :close]
before_filter :check_api_writable, :only => [:create, :update, :delete, :upload, :include]
before_filter :check_api_readable, :except => [:create, :update, :delete, :upload, :download, :query]
after_filter :compress_output
# Help methods for checking boundary sanity and area size
include MapBoundary
# Helper methods for checking consistency
include ConsistencyValidations
# Create a changeset from XML.
def create
if request.put?
cs = Changeset.from_xml(request.raw_post, true)
if cs
cs.user_id = @user.id
cs.save_with_tags!
render :text => cs.id.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
else
render :nothing => true, :status => :method_not_allowed
end
end
##
# Return XML giving the basic info about the changeset. Does not
# return anything about the nodes, ways and relations in the changeset.
def read
begin
changeset = Changeset.find(params[:id])
render :text => changeset.to_xml.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
end
##
# marks a changeset as closed. this may be called multiple times
# on the same changeset, so is idempotent.
def close
unless request.put?
render :nothing => true, :status => :method_not_allowed
return
end
changeset = Changeset.find(params[:id])
check_changeset_consistency(changeset, @user)
# to close the changeset, we'll just set its closed_at time to
# now. this might not be enough if there are concurrency issues,
# but we'll have to wait and see.
changeset.set_closed_time_now
changeset.save!
render :nothing => true
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# insert a (set of) points into a changeset bounding box. this can only
# increase the size of the bounding box. this is a hint that clients can
# set either before uploading a large number of changes, or changes that
# the client (but not the server) knows will affect areas further away.
def expand_bbox
# only allow POST requests, because although this method is
# idempotent, there is no "document" to PUT really...
if request.post?
cs = Changeset.find(params[:id])
check_changeset_consistency(cs, @user)
# keep an array of lons and lats
lon = Array.new
lat = Array.new
# the request is in pseudo-osm format... this is kind-of an
# abuse, maybe should change to some other format?
doc = XML::Parser.string(request.raw_post).parse
doc.find("//osm/node").each do |n|
lon << n['lon'].to_f * GeoRecord::SCALE
lat << n['lat'].to_f * GeoRecord::SCALE
end
# add the existing bounding box to the lon-lat array
lon << cs.min_lon unless cs.min_lon.nil?
lat << cs.min_lat unless cs.min_lat.nil?
lon << cs.max_lon unless cs.max_lon.nil?
lat << cs.max_lat unless cs.max_lat.nil?
# collapse the arrays to minimum and maximum
cs.min_lon, cs.min_lat, cs.max_lon, cs.max_lat =
lon.min, lat.min, lon.max, lat.max
# save the larger bounding box and return the changeset, which
# will include the bigger bounding box.
cs.save!
render :text => cs.to_xml.to_s, :content_type => "text/xml"
else
render :nothing => true, :status => :method_not_allowed
end
rescue LibXML::XML::Error, ArgumentError => ex
raise OSM::APIBadXMLError.new("osm", xml, ex.message)
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# Upload a diff in a single transaction.
#
# This means that each change within the diff must succeed, i.e: that
# each version number mentioned is still current. Otherwise the entire
# transaction *must* be rolled back.
#
# Furthermore, each element in the diff can only reference the current
# changeset.
#
# Returns: a diffResult document, as described in
# http://wiki.openstreetmap.org/index.php/OSM_Protocol_Version_0.6
def upload
# only allow POST requests, as the upload method is most definitely
# not idempotent, as several uploads with placeholder IDs will have
# different side-effects.
# see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.2
unless request.post?
render :nothing => true, :status => :method_not_allowed
return
end
changeset = Changeset.find(params[:id])
check_changeset_consistency(changeset, @user)
diff_reader = DiffReader.new(request.raw_post, changeset)
Changeset.transaction do
result = diff_reader.commit
render :text => result.to_s, :content_type => "text/xml"
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# download the changeset as an osmChange document.
#
# to make it easier to revert diffs it would be better if the osmChange
# format were reversible, i.e: contained both old and new versions of
# modified elements. but it doesn't at the moment...
#
# this method cannot order the database changes fully (i.e: timestamp and
# version number may be too coarse) so the resulting diff may not apply
# to a different database. however since changesets are not atomic this
# behaviour cannot be guaranteed anyway and is the result of a design
# choice.
def download
changeset = Changeset.find(params[:id])
# get all the elements in the changeset and stick them in a big array.
elements = [changeset.old_nodes,
changeset.old_ways,
changeset.old_relations].flatten
# sort the elements by timestamp and version number, as this is the
# almost sensible ordering available. this would be much nicer if
# global (SVN-style) versioning were used - then that would be
# unambiguous.
elements.sort! do |a, b|
if (a.timestamp == b.timestamp)
a.version <=> b.version
else
a.timestamp <=> b.timestamp
end
end
# create an osmChange document for the output
result = OSM::API.new.get_xml_doc
result.root.name = "osmChange"
# generate an output element for each operation. note: we avoid looking
# at the history because it is simpler - but it would be more correct to
# check these assertions.
elements.each do |elt|
result.root <<
if (elt.version == 1)
# first version, so it must be newly-created.
created = XML::Node.new "create"
created << elt.to_xml_node
else
# get the previous version from the element history
prev_elt = elt.class.find(:first, :conditions =>
['id = ? and version = ?',
elt.id, elt.version])
unless elt.visible
# if the element isn't visible then it must have been deleted, so
# output the *previous* XML
deleted = XML::Node.new "delete"
deleted << prev_elt.to_xml_node
else
# must be a modify, for which we don't need the previous version
# yet...
modified = XML::Node.new "modify"
modified << elt.to_xml_node
end
end
end
render :text => result.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# query changesets by bounding box, time, user or open/closed status.
def query
# create the conditions that the user asked for. some or all of
# these may be nil.
conditions = conditions_bbox(params['bbox'])
conditions = cond_merge conditions, conditions_user(params['user'])
conditions = cond_merge conditions, conditions_time(params['time'])
conditions = cond_merge conditions, conditions_open(params['open'])
conditions = cond_merge conditions, conditions_closed(params['closed'])
# create the results document
results = OSM::API.new.get_xml_doc
# add all matching changesets to the XML results document
Changeset.find(:all,
:conditions => conditions,
:limit => 100,
:order => 'created_at desc').each do |cs|
results.root << cs.to_xml_node
end
render :text => results.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# updates a changeset's tags. none of the changeset's attributes are
# user-modifiable, so they will be ignored.
#
# changesets are not (yet?) versioned, so we don't have to deal with
# history tables here. changesets are locked to a single user, however.
#
# after succesful update, returns the XML of the changeset.
def update
# request *must* be a PUT.
unless request.put?
render :nothing => true, :status => :method_not_allowed
return
end
changeset = Changeset.find(params[:id])
new_changeset = Changeset.from_xml(request.raw_post)
unless new_changeset.nil?
check_changeset_consistency(changeset, @user)
changeset.update_from(new_changeset, @user)
render :text => changeset.to_xml, :mime_type => "text/xml"
else
render :nothing => true, :status => :bad_request
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
##
# list edits (open changesets) in reverse chronological order
def list
conditions = conditions_nonempty
# @changesets = Changeset.find(:all, :order => "closed_at DESC", :conditions => ['closed_at < ?', DateTime.now], :limit=> 20)
#@edit_pages, @edits = paginate(:changesets,
# :include => [:user, :changeset_tags],
# :conditions => conditions,
# :order => "changesets.created_at DESC",
# :per_page => 20)
#
@edits = Changeset.find(:all,
:order => "changesets.created_at DESC",
:conditions => conditions,
:limit => 20)
end
##
# list edits (changesets) belonging to a user
def list_user
user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
if user
@display_name = user.display_name
if not user.data_public? and @user != user
@edits = nil
render
else
conditions = cond_merge conditions, ['user_id = ?', user.id]
conditions = cond_merge conditions, conditions_nonempty
@edit_pages, @edits = paginate(:changesets,
:include => [:user, :changeset_tags],
:conditions => conditions,
:order => "changesets.created_at DESC",
:per_page => 20)
end
else
@not_found_user = params[:display_name]
render :template => 'user/no_such_user', :status => :not_found
end
end
##
# list changesets in a bbox
def list_bbox
# support 'bbox' param or alternatively 'minlon', 'minlat' etc
if params['bbox']
bbox = params['bbox']
elsif params['minlon'] and params['minlat'] and params['maxlon'] and params['maxlat']
bbox = h(params['minlon']) + ',' + h(params['minlat']) + ',' + h(params['maxlon']) + ',' + h(params['maxlat'])
else
#TODO: fix bugs in location determination for history tab (and other tabs) then uncomment this redirect
#redirect_to :action => 'list'
end
conditions = conditions_bbox(bbox);
conditions = cond_merge conditions, conditions_nonempty
@edit_pages, @edits = paginate(:changesets,
:include => [:user, :changeset_tags],
:conditions => conditions,
:order => "changesets.created_at DESC",
:per_page => 20)
@bbox = sanitise_boundaries(bbox.split(/,/)) unless bbox==nil
end
private
#------------------------------------------------------------
# utility functions below.
#------------------------------------------------------------
##
# merge two conditions
def cond_merge(a, b)
if a and b
a_str = a.shift
b_str = b.shift
return [ a_str + " AND " + b_str ] + a + b
elsif a
return a
else b
return b
end
end
##
# if a bounding box was specified then parse it and do some sanity
# checks. this is mostly the same as the map call, but without the
# area restriction.
def conditions_bbox(bbox)
unless bbox.nil?
raise OSM::APIBadUserInput.new("Bounding box should be min_lon,min_lat,max_lon,max_lat") unless bbox.count(',') == 3
bbox = sanitise_boundaries(bbox.split(/,/))
raise OSM::APIBadUserInput.new("Minimum longitude should be less than maximum.") unless bbox[0] <= bbox[2]
raise OSM::APIBadUserInput.new("Minimum latitude should be less than maximum.") unless bbox[1] <= bbox[3]
return ['min_lon < ? and max_lon > ? and min_lat < ? and max_lat > ?',
bbox[2] * GeoRecord::SCALE, bbox[0] * GeoRecord::SCALE, bbox[3]* GeoRecord::SCALE, bbox[1] * GeoRecord::SCALE]
else
return nil
end
end
##
# restrict changesets to those by a particular user
def conditions_user(user)
unless user.nil?
# user input checking, we don't have any UIDs < 1
raise OSM::APIBadUserInput.new("invalid user ID") if user.to_i < 1
u = User.find(user.to_i)
# should be able to get changesets of public users only, or
# our own changesets regardless of public-ness.
unless u.data_public?
# get optional user auth stuff so that users can see their own
# changesets if they're non-public
setup_user_auth
raise OSM::APINotFoundError if @user.nil? or @user.id != u.id
end
return ['user_id = ?', u.id]
else
return nil
end
end
##
# restrict changes to those closed during a particular time period
def conditions_time(time)
unless time.nil?
# if there is a range, i.e: comma separated, then the first is
# low, second is high - same as with bounding boxes.
if time.count(',') == 1
# check that we actually have 2 elements in the array
times = time.split(/,/)
raise OSM::APIBadUserInput.new("bad time range") if times.size != 2
from, to = times.collect { |t| DateTime.parse(t) }
return ['closed_at >= ? and created_at <= ?', from, to]
else
# if there is no comma, assume its a lower limit on time
return ['closed_at >= ?', DateTime.parse(time)]
end
else
return nil
end
# stupid DateTime seems to throw both of these for bad parsing, so
# we have to catch both and ensure the correct code path is taken.
rescue ArgumentError => ex
raise OSM::APIBadUserInput.new(ex.message.to_s)
rescue RuntimeError => ex
raise OSM::APIBadUserInput.new(ex.message.to_s)
end
##
# return changesets which are open (haven't been closed yet)
# we do this by seeing if the 'closed at' time is in the future. Also if we've
# hit the maximum number of changes then it counts as no longer open.
# if parameter 'open' is nill then open and closed changsets are returned
def conditions_open(open)
return open.nil? ? nil : ['closed_at >= ? and num_changes <= ?',
Time.now.getutc, Changeset::MAX_ELEMENTS]
end
##
# query changesets which are closed
# ('closed at' time has passed or changes limit is hit)
def conditions_closed(closed)
return closed.nil? ? nil : ['closed_at < ? and num_changes > ?',
Time.now.getutc, Changeset::MAX_ELEMENTS]
end
##
# eliminate empty changesets (where the bbox has not been set)
# this should be applied to all changeset list displays
def conditions_nonempty()
return ['min_lat IS NOT NULL']
end
end

View file

@ -0,0 +1,9 @@
class ChangesetTagController < ApplicationController
layout 'site'
def search
@tags = ChangesetTag.find(:all, :limit => 11, :conditions => ["match(v) against (?)", params[:query][:query].to_s] )
end
end

View file

@ -39,6 +39,8 @@ class DiaryEntryController < ApplicationController
redirect_to :controller => 'diary_entry', :action => 'view', :id => params[:id]
end
end
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
def comment
@ -55,7 +57,7 @@ class DiaryEntryController < ApplicationController
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"
@ -71,7 +73,7 @@ class DiaryEntryController < ApplicationController
else
@title = "Users' diaries"
@entry_pages, @entries = paginate(:diary_entries, :include => :user,
:conditions => "users.visible = 1",
:conditions => ["users.visible = ?", true],
:order => 'created_at DESC',
:per_page => 20)
end
@ -79,13 +81,13 @@ class DiaryEntryController < ApplicationController
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)
@title = "OpenStreetMap diary entries for #{user.display_name}"
@description = "Recent OpenStreetmap diary entries from #{user.display_name}"
@link = "http://www.openstreetmap.org/user/#{user.display_name}/diary"
@link = "http://#{SERVER_URL}/user/#{user.display_name}/diary"
render :content_type => Mime::RSS
else
@ -93,21 +95,22 @@ class DiaryEntryController < ApplicationController
end
else
@entries = DiaryEntry.find(:all, :include => :user,
:conditions => "users.visible = 1",
:conditions => ["users.visible = ?", true],
:order => 'created_at DESC', :limit => 20)
@title = "OpenStreetMap diary entries"
@description = "Recent diary entries from users of OpenStreetMap"
@link = "http://www.openstreetmap.org/diary"
@link = "http://#{SERVER_URL}/diary"
render :content_type => Mime::RSS
end
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]])
@title = "Users' diaries | #{params[:display_name]}"
else
@not_found_user = params[:display_name]

View file

@ -2,18 +2,24 @@ class ExportController < ApplicationController
def start
end
#When the user clicks 'Export' we redirect to a URL which generates the export download
def finish
bbox = BoundingBox.new(params[:minlon], params[:minlat], params[:maxlon], params[:maxlat])
format = params[:format]
if format == "osm"
#redirect to API map get
redirect_to "http://api.openstreetmap.org/api/#{API_VERSION}/map?bbox=#{bbox}"
elsif format == "mapnik"
#redirect to a special 'export' cgi script
format = params[:mapnik_format]
scale = params[:mapnik_scale]
redirect_to "http://tile.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}"
elsif format == "osmarender"
#redirect to the t@h 'MapOf' service
format = params[:osmarender_format]
zoom = params[:osmarender_zoom].to_i
width = bbox.slippy_width(zoom).to_i

View file

@ -6,13 +6,18 @@ class MessageController < ApplicationController
before_filter :check_database_readable
before_filter :check_database_writable, :only => [:new, :reply, :mark]
# Allow the user to write a new message to another user. This action also
# deals with the sending of that message to the other user when the user
# clicks send.
# The user_id param is the id of the user that the message is being sent to.
def new
@title = 'send message'
@to_user = User.find(params[:user_id])
if params[:message]
@message = Message.new(params[:message])
@message.to_user_id = params[:user_id]
@message.to_user_id = @to_user.id
@message.from_user_id = @user.id
@message.sent_on = Time.now
@message.sent_on = Time.now.getutc
if @message.save
flash[:notice] = 'Message sent'
@ -22,27 +27,32 @@ class MessageController < ApplicationController
else
@title = params[:title]
end
rescue ActiveRecord::RecordNotFound
render :action => 'no_such_user', :status => :not_found
end
# Allow the user to reply to another message.
def reply
message = Message.find(params[:message_id], :conditions => ["to_user_id = ? or from_user_id = ?", @user.id, @user.id ])
@body = "On #{message.sent_on} #{message.sender.display_name} wrote:\n\n#{message.body.gsub(/^/, '> ')}"
@title = "Re: #{message.title.sub(/^Re:\s*/, '')}"
@user_id = message.from_user_id
@to_user = User.find(message.from_user_id)
render :action => 'new'
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
render :action => 'no_such_user', :status => :not_found
end
# Show a message
def read
@title = 'read message'
@message = Message.find(params[:message_id], :conditions => ["to_user_id = ? or from_user_id = ?", @user.id, @user.id ])
@message.message_read = 1 if @message.to_user_id == @user.id
@message.message_read = true if @message.to_user_id == @user.id
@message.save
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
render :action => 'no_such_user', :status => :not_found
end
# Display the list of messages that have been sent to the user.
def inbox
@title = 'inbox'
if @user and params[:display_name] == @user.display_name
@ -51,6 +61,7 @@ class MessageController < ApplicationController
end
end
# Display the list of messages that the user has sent to other users.
def outbox
@title = 'outbox'
if @user and params[:display_name] == @user.display_name
@ -59,15 +70,16 @@ class MessageController < ApplicationController
end
end
# Set the message as being read or unread.
def mark
if params[:message_id]
id = params[:message_id]
message = Message.find_by_id(id)
if params[:mark] == 'unread'
message_read = 0
message_read = false
mark_type = 'unread'
else
message_read = 1
message_read = true
mark_type = 'read'
end
message.message_read = message_read
@ -76,5 +88,7 @@ class MessageController < ApplicationController
redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
end
end
rescue ActiveRecord::RecordNotFound
render :action => 'no_such_user', :status => :not_found
end
end

View file

@ -5,26 +5,28 @@ class NodeController < ApplicationController
session :off
before_filter :authorize, :only => [:create, :update, :delete]
before_filter :require_public_data, :only => [:create, :update, :delete]
before_filter :check_api_writable, :only => [:create, :update, :delete]
before_filter :check_api_readable, :except => [:create, :update, :delete]
after_filter :compress_output
# Create a node from XML.
def create
if request.put?
node = Node.from_xml(request.raw_post, true)
begin
if request.put?
node = Node.from_xml(request.raw_post, true)
if node
node.user_id = @user.id
node.visible = true
node.save_with_history!
render :text => node.id.to_s, :content_type => "text/plain"
if node
node.create_with_history @user
render :text => node.id.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
else
render :nothing => true, :status => :bad_request
render :nothing => true, :status => :method_not_allowed
end
else
render :nothing => true, :status => :method_not_allowed
rescue OSM::APIError => ex
render ex.render_opts
end
end
@ -32,7 +34,7 @@ class NodeController < ApplicationController
def read
begin
node = Node.find(params[:id])
if node.visible
if node.visible?
response.headers['Last-Modified'] = node.timestamp.rfc822
render :text => node.to_xml.to_s, :content_type => "text/xml"
else
@ -42,7 +44,7 @@ class NodeController < ApplicationController
render :nothing => true, :status => :not_found
end
end
# Update a node from given XML
def update
begin
@ -50,49 +52,40 @@ class NodeController < ApplicationController
new_node = Node.from_xml(request.raw_post)
if new_node and new_node.id == node.id
node.user_id = @user.id
node.latitude = new_node.latitude
node.longitude = new_node.longitude
node.tags = new_node.tags
node.visible = true
node.save_with_history!
node.update_from(new_node, @user)
render :text => node.version.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
rescue OSM::APIError => ex
render ex.render_opts
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
end
render :nothing => true
# Delete a node. Doesn't actually delete it, but retains its history
# in a wiki-like way. We therefore treat it like an update, so the delete
# method returns the new version number.
def delete
begin
node = Node.find(params[:id])
new_node = Node.from_xml(request.raw_post)
if new_node and new_node.id == node.id
node.delete_with_history!(new_node, @user)
render :text => node.version.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue OSM::APIError => ex
render ex.render_opts
end
end
# Delete a node. Doesn't actually delete it, but retains its history in a wiki-like way.
# FIXME remove all the fricking SQL
def delete
begin
node = Node.find(params[:id])
if node.visible
if WayNode.find(:first, :joins => "INNER JOIN current_ways ON current_ways.id = current_way_nodes.id", :conditions => [ "current_ways.visible = 1 AND current_way_nodes.node_id = ?", node.id ])
render :text => "", :status => :precondition_failed
elsif RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='node' and member_id=?", params[:id]])
render :text => "", :status => :precondition_failed
else
node.user_id = @user.id
node.visible = 0
node.save_with_history!
render :nothing => true
end
else
render :text => "", :status => :gone
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
end
# WTF does this do?
# Dump the details on many nodes whose ids are given in the "nodes" parameter.
def nodes
ids = params['nodes'].split(',').collect { |n| n.to_i }

View file

@ -22,4 +22,21 @@ class OldNodeController < ApplicationController
render :nothing => true, :status => :internal_server_error
end
end
def version
begin
old_node = OldNode.find(:first, :conditions => {:id => params[:id], :version => params[:version]} )
response.headers['Last-Modified'] = old_node.timestamp.rfc822
doc = OSM::API.new.get_xml_doc
doc.root << old_node.to_xml_node
render :text => doc.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
end

View file

@ -2,6 +2,7 @@ class OldRelationController < ApplicationController
require 'xml/libxml'
session :off
before_filter :check_api_readable
after_filter :compress_output
def history
@ -20,4 +21,21 @@ class OldRelationController < ApplicationController
render :nothing => true, :status => :internal_server_error
end
end
def version
begin
old_relation = OldRelation.find(:first, :conditions => {:id => params[:id], :version => params[:version]} )
response.headers['Last-Modified'] = old_relation.timestamp.rfc822
doc = OSM::API.new.get_xml_doc
doc.root << old_relation.to_xml_node
render :text => doc.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internetal_service_error
end
end
end

View file

@ -13,7 +13,7 @@ class OldWayController < ApplicationController
way.old_ways.each do |old_way|
doc.root << old_way.to_xml_node
end
end
render :text => doc.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
@ -22,4 +22,21 @@ class OldWayController < ApplicationController
render :nothing => true, :status => :internal_server_error
end
end
def version
begin
old_way = OldWay.find(:first, :conditions => {:id => params[:id], :version => params[:version]} )
response.headers['Last-Modified'] = old_way.timestamp.rfc822
doc = OSM::API.new.get_xml_doc
doc.root << old_way.to_xml_node
render :text => doc.to_s, :content_type => "text/xml"
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
end

View file

@ -3,28 +3,29 @@ class RelationController < ApplicationController
session :off
before_filter :authorize, :only => [:create, :update, :delete]
before_filter :require_public_data, :only => [:create, :update, :delete]
before_filter :check_api_writable, :only => [:create, :update, :delete]
before_filter :check_api_readable, :except => [:create, :update, :delete]
after_filter :compress_output
def create
if request.put?
relation = Relation.from_xml(request.raw_post, true)
begin
if request.put?
relation = Relation.from_xml(request.raw_post, true)
if relation
if !relation.preconditions_ok?
render :text => "", :status => :precondition_failed
else
relation.user_id = @user.id
relation.save_with_history!
render :text => relation.id.to_s, :content_type => "text/plain"
end
# We assume that an exception has been thrown if there was an error
# generating the relation
#if relation
relation.create_with_history @user
render :text => relation.id.to_s, :content_type => "text/plain"
#else
# render :text => "Couldn't get turn the input into a relation.", :status => :bad_request
#end
else
render :nothing => true, :status => :bad_request
render :nothing => true, :status => :method_not_allowed
end
else
render :nothing => true, :status => :method_not_allowed
rescue OSM::APIError => ex
render ex.render_opts
end
end
@ -45,56 +46,38 @@ class RelationController < ApplicationController
end
def update
logger.debug request.raw_post
begin
relation = Relation.find(params[:id])
new_relation = Relation.from_xml(request.raw_post)
if new_relation and new_relation.id == relation.id
if !new_relation.preconditions_ok?
render :text => "", :status => :precondition_failed
else
relation.user_id = @user.id
relation.tags = new_relation.tags
relation.members = new_relation.members
relation.visible = true
relation.save_with_history!
render :nothing => true
end
relation.update_from new_relation, @user
render :text => relation.version.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
rescue OSM::APIError => ex
render ex.render_opts
end
end
def delete
#XXX check if member somewhere!
begin
relation = Relation.find(params[:id])
if relation.visible
if RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='relation' and member_id=?", params[:id]])
render :text => "", :status => :precondition_failed
else
relation.user_id = @user.id
relation.tags = []
relation.members = []
relation.visible = false
relation.save_with_history!
render :nothing => true
end
new_relation = Relation.from_xml(request.raw_post)
if new_relation and new_relation.id == relation.id
relation.delete_with_history!(new_relation, @user)
render :text => relation.version.to_s, :content_type => "text/plain"
else
render :text => "", :status => :gone
render :nothing => true, :status => :bad_request
end
rescue OSM::APIError => ex
render ex.render_opts
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
@ -115,12 +98,12 @@ class RelationController < ApplicationController
# first collect nodes, ways, and relations referenced by this relation.
ways = Way.find_by_sql("select w.* from current_ways w,current_relation_members rm where "+
"rm.member_type='way' and rm.member_id=w.id and rm.id=#{relation.id}");
"rm.member_type='Way' and rm.member_id=w.id and rm.id=#{relation.id}");
nodes = Node.find_by_sql("select n.* from current_nodes n,current_relation_members rm where "+
"rm.member_type='node' and rm.member_id=n.id and rm.id=#{relation.id}");
"rm.member_type='Node' and rm.member_id=n.id and rm.id=#{relation.id}");
# note query is built to exclude self just in case.
relations = Relation.find_by_sql("select r.* from current_relations r,current_relation_members rm where "+
"rm.member_type='relation' and rm.member_id=r.id and rm.id=#{relation.id} and r.id<>rm.id");
"rm.member_type='Relation' and rm.member_id=r.id and rm.id=#{relation.id} and r.id<>rm.id");
# now additionally collect nodes referenced by ways. Note how we recursively
# evaluate ways but NOT relations.
@ -160,8 +143,7 @@ class RelationController < ApplicationController
render :text => doc.to_s, :content_type => "text/xml"
else
render :text => "", :status => :gone
render :nothing => true, :status => :gone
end
rescue ActiveRecord::RecordNotFound
@ -184,27 +166,29 @@ class RelationController < ApplicationController
render :text => doc.to_s, :content_type => "text/xml"
else
render :nothing => true, :status => :bad_request
render :text => "You need to supply a comma separated list of ids.", :status => :bad_request
end
rescue ActiveRecord::RecordNotFound
render :text => "Could not find one of the relations", :status => :not_found
end
def relations_for_way
relations_for_object("way")
relations_for_object("Way")
end
def relations_for_node
relations_for_object("node")
relations_for_object("Node")
end
def relations_for_relation
relations_for_object("relation")
relations_for_object("Relation")
end
def relations_for_object(objtype)
relationids = RelationMember.find(:all, :conditions => ['member_type=? and member_id=?', objtype, params[:id]]).collect { |ws| ws.id }.uniq
relationids = RelationMember.find(:all, :conditions => ['member_type=? and member_id=?', objtype, params[:id]]).collect { |ws| ws.id[0] }.uniq
doc = OSM::API.new.get_xml_doc
Relation.find(relationids).each do |relation|
doc.root << relation.to_xml_node
doc.root << relation.to_xml_node if relation.visible
end
render :text => doc.to_s, :content_type => "text/xml"

View file

@ -1,8 +1,8 @@
class TraceController < ApplicationController
layout 'site'
before_filter :authorize_web
before_filter :require_user, :only => [:mine, :edit, :delete, :make_public]
before_filter :authorize_web
before_filter :require_user, :only => [:mine, :create, :edit, :delete, :make_public]
before_filter :authorize, :only => [:api_details, :api_data, :api_create]
before_filter :check_database_readable, :except => [:api_details, :api_data, :api_create]
before_filter :check_database_writable, :only => [:create, :edit, :delete, :make_public]
@ -15,7 +15,12 @@ class TraceController < ApplicationController
# from display name, pick up user id if one user's traces only
display_name = params[:display_name]
if target_user.nil? and !display_name.blank?
target_user = User.find(:first, :conditions => [ "visible = 1 and display_name = ?", display_name])
target_user = User.find(:first, :conditions => [ "visible = ? and display_name = ?", true, display_name])
if target_user.nil?
@not_found_user = display_name
render :action => 'no_such_user', :status => :not_found
return
end
end
# set title
@ -36,15 +41,15 @@ class TraceController < ApplicationController
# 4 - user's traces, not logged in as that user = all user's public traces
if target_user.nil? # all traces
if @user
conditions = ["(gpx_files.public = 1 OR gpx_files.user_id = ?)", @user.id] #1
conditions = ["(gpx_files.public = ? OR gpx_files.user_id = ?)", true, @user.id] #1
else
conditions = ["gpx_files.public = 1"] #2
conditions = ["gpx_files.public = ?", true] #2
end
else
if @user and @user == target_user
conditions = ["gpx_files.user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
else
conditions = ["gpx_files.public = 1 AND gpx_files.user_id = ?", target_user.id] #4
conditions = ["gpx_files.public = ? AND gpx_files.user_id = ?", true, target_user.id] #4
end
end
@ -55,7 +60,8 @@ class TraceController < ApplicationController
conditions[0] += " AND gpx_files.id IN (#{files.join(',')})"
end
conditions[0] += " AND gpx_files.visible = 1"
conditions[0] += " AND gpx_files.visible = ?"
conditions << true
@trace_pages, @traces = paginate(:traces,
:include => [:user, :tags],
@ -100,26 +106,28 @@ class TraceController < ApplicationController
end
def create
logger.info(params[:trace][:gpx_file].class.name)
if params[:trace][:gpx_file].respond_to?(:read)
do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
params[:trace][:description], params[:trace][:public])
if params[:trace]
logger.info(params[:trace][:gpx_file].class.name)
if params[:trace][:gpx_file].respond_to?(:read)
do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
params[:trace][:description], params[:trace][:public])
if @trace.id
logger.info("id is #{@trace.id}")
flash[:notice] = "Your GPX file has been uploaded and is awaiting insertion in to the database. This will usually happen within half an hour, and an email will be sent to you on completion."
if @trace.id
logger.info("id is #{@trace.id}")
flash[:notice] = "Your GPX file has been uploaded and is awaiting insertion in to the database. This will usually happen within half an hour, and an email will be sent to you on completion."
redirect_to :action => 'mine'
redirect_to :action => 'mine'
end
else
@trace = Trace.new({:name => "Dummy",
:tagstring => params[:trace][:tagstring],
:description => params[:trace][:description],
:public => params[:trace][:public],
:inserted => false, :user => @user,
:timestamp => Time.now.getutc})
@trace.valid?
@trace.errors.add(:gpx_file, "can't be blank")
end
else
@trace = Trace.new({:name => "Dummy",
:tagstring => params[:trace][:tagstring],
:description => params[:trace][:description],
:public => params[:trace][:public],
:inserted => false, :user => @user,
:timestamp => Time.now})
@trace.valid?
@trace.errors.add(:gpx_file, "can't be blank")
end
end
@ -196,7 +204,7 @@ class TraceController < ApplicationController
end
def georss
conditions = ["gpx_files.public = 1"]
conditions = ["gpx_files.public = ?", true]
if params[:display_name]
conditions[0] += " AND users.display_name = ?"
@ -278,12 +286,20 @@ class TraceController < ApplicationController
def api_create
if request.post?
do_create(params[:file], params[:tags], params[:description], params[:public])
tags = params[:tags] || ""
description = params[:description] || ""
pub = params[:public] || false
if params[:file].respond_to?(:read)
do_create(params[:file], tags, description, pub)
if @trace.id
render :text => @trace.id.to_s, :content_type => "text/plain"
elsif @trace.valid?
render :nothing => true, :status => :internal_server_error
if @trace.id
render :text => @trace.id.to_s, :content_type => "text/plain"
elsif @trace.valid?
render :nothing => true, :status => :internal_server_error
else
render :nothing => true, :status => :bad_request
end
else
render :nothing => true, :status => :bad_request
end
@ -313,7 +329,7 @@ private
:public => public,
:inserted => true,
:user => @user,
:timestamp => Time.now
:timestamp => Time.now.getutc
})
# Save the trace object
@ -328,6 +344,17 @@ private
# Remove the file as we have failed to update the database
FileUtils.rm_f(filename)
end
# Finally save whether the user marked the trace as being public
if @trace.public?
if @user.trace_public_default.nil?
@user.preferences.create(:k => "gps.trace.public", :v => "default")
end
else
pref = @user.trace_public_default
pref.destroy unless pref.nil?
end
end
end

View file

@ -83,7 +83,7 @@ class UserController < ApplicationController
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
@ -120,9 +120,21 @@ class UserController < ApplicationController
def new
@title = 'create account'
# The user is logged in already, so don't show them the signup page, instead
# send them to the home page
redirect_to :controller => 'site', :action => 'index' if session[:user]
end
def login
if session[:user]
# The user is logged in already, if the referer param exists, redirect them to that
if params[:referer]
redirect_to params[:referer]
else
redirect_to :controller => 'site', :action => 'index'
end
return
end
@title = 'login'
if params[:user]
email_or_display_name = params[:user][:email]
@ -223,7 +235,7 @@ class UserController < ApplicationController
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
@ -236,7 +248,7 @@ class UserController < ApplicationController
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
@ -258,7 +270,7 @@ class UserController < ApplicationController
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."

View file

@ -5,11 +5,9 @@ class UserPreferenceController < ApplicationController
def read_one
pref = UserPreference.find(@user.id, params[:preference_key])
if pref
render :text => pref.v.to_s
else
render :text => 'OH NOES! PREF NOT FOUND!', :status => 404
end
render :text => pref.v.to_s
rescue ActiveRecord::RecordNotFound => ex
render :text => 'OH NOES! PREF NOT FOUND!', :status => :not_found
end
def update_one
@ -32,6 +30,8 @@ class UserPreferenceController < ApplicationController
UserPreference.delete(@user.id, params[:preference_key])
render :nothing => true
rescue ActiveRecord::RecordNotFound => ex
render :text => "param: #{params[:preference_key]} not found", :status => :not_found
end
# print out all the preferences as a big xml block
@ -54,46 +54,44 @@ class UserPreferenceController < ApplicationController
def update
begin
p = XML::Parser.string(request.raw_post)
doc = p.parse
rescue LibXML::XML::Error, ArgumentError => ex
raise OSM::APIBadXMLError.new("preferences", xml, ex.message)
end
doc = p.parse
prefs = []
prefs = []
keyhash = {}
keyhash = {}
doc.find('//preferences/preference').each do |pt|
pref = UserPreference.new
doc.find('//preferences/preference').each do |pt|
pref = UserPreference.new
unless keyhash[pt['k']].nil? # already have that key
render :text => 'OH NOES! CAN HAS UNIQUE KEYS?', :status => :not_acceptable
return
end
keyhash[pt['k']] = 1
pref.k = pt['k']
pref.v = pt['v']
pref.user_id = @user.id
prefs << pref
unless keyhash[pt['k']].nil? # already have that key
render :text => 'OH NOES! CAN HAS UNIQUE KEYS?', :status => :not_acceptable
end
if prefs.size > 150
render :text => 'Too many preferences', :status => :request_entity_too_large
return
end
keyhash[pt['k']] = 1
# kill the existing ones
UserPreference.delete_all(['user_id = ?', @user.id])
# save the new ones
prefs.each do |pref|
pref.save!
end
rescue Exception => ex
render :text => 'OH NOES! FAIL!: ' + ex.to_s, :status => :internal_server_error
return
pref.k = pt['k']
pref.v = pt['v']
pref.user_id = @user.id
prefs << pref
end
if prefs.size > 150
render :text => 'Too many preferences', :status => :request_entity_too_large
end
# kill the existing ones
UserPreference.delete_all(['user_id = ?', @user.id])
# save the new ones
prefs.each do |pref|
pref.save!
end
render :nothing => true
rescue Exception => ex
render :text => 'OH NOES! FAIL!: ' + ex.to_s, :status => :internal_server_error
end
end

View file

@ -3,28 +3,28 @@ class WayController < ApplicationController
session :off
before_filter :authorize, :only => [:create, :update, :delete]
before_filter :require_public_data, :only => [:create, :update, :delete]
before_filter :check_api_writable, :only => [:create, :update, :delete]
before_filter :check_api_readable, :except => [:create, :update, :delete]
after_filter :compress_output
def create
if request.put?
way = Way.from_xml(request.raw_post, true)
if way
if !way.preconditions_ok?
render :text => "", :status => :precondition_failed
else
way.user_id = @user.id
way.save_with_history!
begin
if request.put?
way = Way.from_xml(request.raw_post, true)
if way
way.create_with_history @user
render :text => way.id.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
else
render :nothing => true, :status => :bad_request
render :nothing => true, :status => :method_not_allowed
end
else
render :nothing => true, :status => :method_not_allowed
rescue OSM::APIError => ex
logger.warn request.raw_post
render ex.render_opts
end
end
@ -39,6 +39,8 @@ class WayController < ApplicationController
else
render :text => "", :status => :gone
end
rescue OSM::APIError => ex
render ex.render_opts
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
@ -50,20 +52,14 @@ class WayController < ApplicationController
new_way = Way.from_xml(request.raw_post)
if new_way and new_way.id == way.id
if !new_way.preconditions_ok?
render :text => "", :status => :precondition_failed
else
way.user_id = @user.id
way.tags = new_way.tags
way.nds = new_way.nds
way.visible = true
way.save_with_history!
render :nothing => true
end
way.update_from(new_way, @user)
render :text => way.version.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
rescue OSM::APIError => ex
logger.warn request.raw_post
render ex.render_opts
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
@ -73,14 +69,16 @@ class WayController < ApplicationController
def delete
begin
way = Way.find(params[:id])
way.delete_with_relations_and_history(@user)
new_way = Way.from_xml(request.raw_post)
# if we get here, all is fine, otherwise something will catch below.
render :nothing => true
rescue OSM::APIAlreadyDeletedError
render :text => "", :status => :gone
rescue OSM::APIPreconditionFailedError
render :text => "", :status => :precondition_failed
if new_way and new_way.id == way.id
way.delete_with_history!(new_way, @user)
render :text => way.version.to_s, :content_type => "text/plain"
else
render :nothing => true, :status => :bad_request
end
rescue OSM::APIError => ex
render ex.render_opts
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
@ -92,7 +90,7 @@ class WayController < ApplicationController
if way.visible
nd_ids = way.nds + [-1]
nodes = Node.find(:all, :conditions => "visible = 1 AND id IN (#{nd_ids.join(',')})")
nodes = Node.find(:all, :conditions => ["visible = ? AND id IN (#{nd_ids.join(',')})", true])
# Render
doc = OSM::API.new.get_xml_doc
@ -130,13 +128,19 @@ class WayController < ApplicationController
end
end
##
# returns all the ways which are currently using the node given in the
# :id parameter. note that this used to return deleted ways as well, but
# this seemed not to be the expected behaviour, so it was removed.
def ways_for_node
wayids = WayNode.find(:all, :conditions => ['node_id = ?', params[:id]]).collect { |ws| ws.id[0] }.uniq
wayids = WayNode.find(:all,
:conditions => ['node_id = ?', params[:id]]
).collect { |ws| ws.id[0] }.uniq
doc = OSM::API.new.get_xml_doc
Way.find(wayids).each do |way|
doc.root << way.to_xml_node
doc.root << way.to_xml_node if way.visible
end
render :text => doc.to_s, :content_type => "text/xml"