X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/538bfed8a61a576e44d8cc71d7727c0310bcf238..a5d14a1815b26cbec356441876d533163e5de3b2:/app/controllers/api/changesets_controller.rb diff --git a/app/controllers/api/changesets_controller.rb b/app/controllers/api/changesets_controller.rb index 92690a75e..0dffd4de2 100644 --- a/app/controllers/api/changesets_controller.rb +++ b/app/controllers/api/changesets_controller.rb @@ -1,31 +1,43 @@ # The ChangesetController is the RESTful interface to Changeset objects module Api - class ChangesetsController < ApplicationController - layout "site" + class ChangesetsController < ApiController require "xml/libxml" - skip_before_action :verify_authenticity_token + before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe] + before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe] before_action :authorize, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe] - before_action :api_deny_access_handler, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe, :expand_bbox] authorize_resource before_action :require_public_data, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe] - before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe] - before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe] - before_action(:only => [:index, :feed]) { |c| c.check_database_readable(true) } + before_action :set_request_formats, :except => [:create, :close, :upload] + around_action :api_call_handle_error around_action :api_call_timeout, :except => [:upload] # Helper methods for checking consistency include ConsistencyValidations + ## + # Return XML giving the basic info about the changeset. Does not + # return anything about the nodes, ways and relations in the changeset. + def show + @changeset = Changeset.find(params[:id]) + @include_discussion = params[:include_discussion].presence + render "changeset" + + respond_to do |format| + format.xml + format.json + end + end + # Create a changeset from XML. def create assert_method :put - cs = Changeset.from_xml(request.raw_post, true) + cs = Changeset.from_xml(request.raw_post, :create => true) # Assume that Changeset.from_xml has thrown an exception if there is an error parsing the xml cs.user = current_user @@ -37,15 +49,6 @@ module Api render :plain => cs.id.to_s end - ## - # Return XML giving the basic info about the changeset. Does not - # return anything about the nodes, ways and relations in the changeset. - def show - @changeset = Changeset.find(params[:id]) - @include_discussion = params[:include_discussion].presence - render "changesets/changeset" - end - ## # marks a changeset as closed. this may be called multiple times # on the same changeset, so is idempotent. @@ -64,50 +67,6 @@ module Api head :ok 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... - assert_method :post - - cs = Changeset.find(params[:id]) - check_changeset_consistency(cs, current_user) - - # keep an array of lons and lats - lon = [] - lat = [] - - # 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, :options => XML::Parser::Options::NOERROR).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 = lon.min - cs.min_lat = lat.min - cs.max_lon = lon.max - cs.max_lat = lat.max - - # save the larger bounding box and return the changeset, which - # will include the bigger bounding box. - cs.save! - @changeset = cs - render "changesets/changeset" - end - ## # Upload a diff in a single transaction. # @@ -170,35 +129,29 @@ module Api end end - # create changeset and user caches - changeset_cache = {} - user_display_name_cache = {} - - # 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. + @created = [] + @modified = [] + @deleted = [] + 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(changeset_cache, user_display_name_cache) - elsif elt.visible - # must be a modify - modified = XML::Node.new "modify" - modified << elt.to_xml_node(changeset_cache, user_display_name_cache) - else - # if the element isn't visible then it must have been deleted - deleted = XML::Node.new "delete" - deleted << elt.to_xml_node(changeset_cache, user_display_name_cache) - end + if elt.version == 1 + # first version, so it must be newly-created. + @created << elt + elsif elt.visible + # must be a modify + @modified << elt + else + # if the element isn't visible then it must have been deleted + @deleted << elt + end end - render :xml => result.to_s + respond_to do |format| + format.xml + end end ## @@ -218,11 +171,16 @@ module Api changesets = conditions_ids(changesets, params["changesets"]) # sort and limit the changesets - changesets = changesets.order("created_at DESC").limit(100) + changesets = changesets.order("created_at DESC").limit(result_limit) # preload users, tags and comments, and render result @changesets = changesets.preload(:user, :changeset_tags, :comments) - render "changesets/changesets" + render "changesets" + + respond_to do |format| + format.xml + format.json + end end ## @@ -242,7 +200,12 @@ module Api check_changeset_consistency(@changeset, current_user) @changeset.update_from(new_changeset, current_user) - render "changesets/changeset" + render "changeset" + + respond_to do |format| + format.xml + format.json + end end ## @@ -263,7 +226,12 @@ module Api # Return a copy of the updated changeset @changeset = changeset - render "changesets/changeset" + render "changeset" + + respond_to do |format| + format.xml + format.json + end end ## @@ -284,7 +252,12 @@ module Api # Return a copy of the updated changeset @changeset = changeset - render "changesets/changeset" + render "changeset" + + respond_to do |format| + format.xml + format.json + end end private @@ -356,21 +329,19 @@ module Api # low, second is high - same as with bounding boxes. # check that we actually have 2 elements in the array - times = time.split(/,/) + times = time.split(",") raise OSM::APIBadUserInput, "bad time range" if times.size != 2 - from, to = times.collect { |t| Time.parse(t) } + from, to = times.collect { |t| Time.parse(t).utc } changesets.where("closed_at >= ? and created_at <= ?", from, to) else # if there is no comma, assume its a lower limit on time - changesets.where("closed_at >= ?", Time.parse(time)) + changesets.where("closed_at >= ?", Time.parse(time).utc) end # stupid Time 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, ex.message.to_s - rescue RuntimeError => ex - raise OSM::APIBadUserInput, ex.message.to_s + rescue ArgumentError, RuntimeError => e + raise OSM::APIBadUserInput, e.message.to_s end ## @@ -383,7 +354,7 @@ module Api changesets else changesets.where("closed_at >= ? and num_changes <= ?", - Time.now.getutc, Changeset::MAX_ELEMENTS) + Time.now.utc, Changeset::MAX_ELEMENTS) end end @@ -395,7 +366,7 @@ module Api changesets else changesets.where("closed_at < ? or num_changes > ?", - Time.now.getutc, Changeset::MAX_ELEMENTS) + Time.now.utc, Changeset::MAX_ELEMENTS) end end @@ -412,5 +383,19 @@ module Api changesets.where(:id => ids) end end + + ## + # Get the maximum number of results to return + def result_limit + if params[:limit] + if params[:limit].to_i.positive? && params[:limit].to_i <= Settings.max_changeset_query_limit + params[:limit].to_i + else + raise OSM::APIBadUserInput, "Changeset limit must be between 1 and #{Settings.max_changeset_query_limit}" + end + else + Settings.default_changeset_query_limit + end + end end end