]> git.openstreetmap.org Git - rails.git/commitdiff
Merge branch 'pull/5715'
authorAnton Khorev <tony29@yandex.ru>
Sun, 23 Feb 2025 23:15:24 +0000 (02:15 +0300)
committerAnton Khorev <tony29@yandex.ru>
Sun, 23 Feb 2025 23:15:24 +0000 (02:15 +0300)
18 files changed:
app/abilities/api_ability.rb
app/controllers/api/changeset_comments_controller.rb
app/controllers/api/changesets/downloads_controller.rb [new file with mode: 0644]
app/controllers/api/changesets_controller.rb
app/controllers/users/lists_controller.rb
app/views/api/changesets/downloads/show.xml.builder [moved from app/views/api/changesets/download.xml.builder with 55% similarity]
app/views/changesets/index.atom.builder
app/views/changesets/show.html.erb
app/views/users/lists/show.html.erb
config/initializers/cors.rb
config/locales/en.yml
config/routes.rb
test/controllers/api/changeset_comments_controller_test.rb
test/controllers/api/changesets/downloads_controller_test.rb [new file with mode: 0644]
test/controllers/api/changesets_controller_test.rb
test/controllers/api/relations_controller_test.rb
test/controllers/users/lists_controller_test.rb
yarn.lock

index edf051faeb8f324b1a1767bbafeff07149dd222b..9a7bf254a78fa038c5e0fc2c09e6d10b40b7d867 100644 (file)
@@ -10,7 +10,7 @@ class ApiAbility
       can [:read, :feed, :search], Note
       can :create, Note unless user
 
-      can [:read, :download], Changeset
+      can :read, Changeset
       can :read, ChangesetComment
       can :read, Tracepoint
       can :read, User
index 808ac97ea3418257445177caeb8615cc2574ff78..86abff265e7da0794b1db2b62087b4bc89e1bacb 100644 (file)
@@ -24,16 +24,16 @@ module Api
     # Add a comment to a changeset
     def create
       # Check the arguments are sane
-      raise OSM::APIBadUserInput, "No id was given" unless params[:id]
+      raise OSM::APIBadUserInput, "No id was given" unless params[:changeset_id]
       raise OSM::APIBadUserInput, "No text was given" if params[:text].blank?
       raise OSM::APIRateLimitExceeded if rate_limit_exceeded?
 
       # Extract the arguments
-      id = params[:id].to_i
+      changeset_id = params[:changeset_id].to_i
       body = params[:text]
 
       # Find the changeset and check it is valid
-      changeset = Changeset.find(id)
+      changeset = Changeset.find(changeset_id)
       raise OSM::APIChangesetNotYetClosedError, changeset if changeset.open?
 
       # Add a comment to the changeset
diff --git a/app/controllers/api/changesets/downloads_controller.rb b/app/controllers/api/changesets/downloads_controller.rb
new file mode 100644 (file)
index 0000000..1abc9e4
--- /dev/null
@@ -0,0 +1,75 @@
+module Api
+  module Changesets
+    class DownloadsController < ApiController
+      before_action :setup_user_auth
+
+      authorize_resource :changeset
+
+      before_action :set_request_formats
+
+      ##
+      # 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 show
+        changeset = Changeset.find(params[:changeset_id])
+
+        # get all the elements in the changeset which haven't been redacted
+        # and stick them in a big array.
+        elements = if show_redactions?
+                     [changeset.old_nodes,
+                      changeset.old_ways,
+                      changeset.old_relations].flatten
+                   else
+                     [changeset.old_nodes.unredacted,
+                      changeset.old_ways.unredacted,
+                      changeset.old_relations.unredacted].flatten
+                   end
+
+        # 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_by! { |e| [e.timestamp, e.version] }
+
+        # 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|
+          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
+
+        respond_to do |format|
+          format.xml
+        end
+      end
+
+      private
+
+      def show_redactions?
+        current_user&.moderator? && params[:show_redactions] == "true"
+      end
+    end
+  end
+end
index 3df7b75cea752aeb11a0681b728377d6f6a0d0e0..517cff47326d28853cacd96416c718c8b5d81b69 100644 (file)
@@ -130,58 +130,6 @@ module Api
       end
     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 which haven't been redacted
-      # and stick them in a big array.
-      elements = [changeset.old_nodes.unredacted,
-                  changeset.old_ways.unredacted,
-                  changeset.old_relations.unredacted].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_by! { |e| [e.timestamp, e.version] }
-
-      # 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|
-        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
-
-      respond_to do |format|
-        format.xml
-      end
-    end
-
     ##
     # updates a changeset's tags. none of the changeset's attributes are
     # user-modifiable, so they will be ignored.
index a2f35e9b213a8f5ea91a4a8ecbbe76ca1e889c97..7e3fa2a32801cb70854c8e4fc8b3f0dea9d70d66 100644 (file)
@@ -13,10 +13,11 @@ module Users
     ##
     # display a list of users matching specified criteria
     def show
-      @params = params.permit(:status, :ip, :before, :after)
+      @params = params.permit(:status, :username, :ip, :before, :after)
 
       users = User.all
       users = users.where(:status => @params[:status]) if @params[:status].present?
+      users = users.where("LOWER(email) = LOWER(?) OR LOWER(NORMALIZE(display_name, NFKC)) = LOWER(NORMALIZE(?, NFKC))", @params[:username], @params[:username]) if @params[:username].present?
       users = users.where("creation_address <<= ?", @params[:ip]) if @params[:ip].present?
 
       @users_count = users.limit(501).count
similarity index 55%
rename from app/views/api/changesets/download.xml.builder
rename to app/views/api/changesets/downloads/show.xml.builder
index 1e400cd9feceef34b4d857e31fa0a6d6497418c9..88e05b587c4c08600cabef92efdf8770169c1453 100644 (file)
@@ -3,17 +3,17 @@ xml.instruct! :xml, :version => "1.0"
 xml.osmChange(OSM::API.new.xml_root_attributes) do |osm|
   @created.each do |elt|
     osm.create do |create|
-      create << render(elt)
+      create << render(:partial => "api/#{elt.to_partial_path}", :object => elt)
     end
   end
   @modified.each do |elt|
     osm.modify do |modify|
-      modify << render(elt)
+      modify << render(:partial => "api/#{elt.to_partial_path}", :object => elt)
     end
   end
   @deleted.each do |elt|
     osm.delete do |delete|
-      delete << render(elt)
+      delete << render(:partial => "api/#{elt.to_partial_path}", :object => elt)
     end
   end
 end
index c8ffe1a81c973a852af251c1147fa4e8d024094d..6556f12bfe1641f54d79522abfb71510a2d3fb9b 100644 (file)
@@ -18,10 +18,10 @@ atom_feed(:language => I18n.locale, :schema_date => 2009,
   @changesets.each do |changeset|
     feed.entry(changeset, :updated => changeset.closed_at, :id => changeset_url(changeset.id, :only_path => false)) do |entry|
       entry.link :rel => "alternate",
-                 :href => changeset_show_url(changeset, :only_path => false),
+                 :href => api_changeset_url(changeset, :only_path => false),
                  :type => "application/osm+xml"
       entry.link :rel => "alternate",
-                 :href => changeset_download_url(changeset, :only_path => false),
+                 :href => api_changeset_download_url(changeset, :only_path => false),
                  :type => "application/osmChange+xml"
 
       if !changeset.tags.empty? && changeset.tags.key?("comment")
index 167bcb5cb807d5fc2d147a049853b2284125d25b..3f0d08476da73f7d00745401ea3e95212cdd3d56 100644 (file)
@@ -81,7 +81,7 @@
                          :name => "comment",
                          :disabled => true,
                          :data => { :method => "POST",
-                                    :url => changeset_comment_url(@changeset) } %>
+                                    :url => api_changeset_changeset_comments_path(@changeset) } %>
         </div>
       </form>
     <% else %>
 </div>
 
 <div class='secondary-actions'>
-  <%= link_to(t(".changesetxml"), :controller => "api/changesets", :action => "show") %>
+  <%= link_to t(".changesetxml"), api_changeset_path(@changeset) %>
   &middot;
-  <%= link_to(t(".osmchangexml"), :controller => "api/changesets", :action => "download") %>
+  <%= link_to t(".osmchangexml"), api_changeset_download_path(@changeset) %>
 </div>
 
 <% if @next_by_user || @prev_by_user %>
index dd037c7af6c3a13dee647bf9ba3e077ca658be7e..c3d15d18afe6656385195801474c89a299f5f4cb 100644 (file)
                      :data => { :behavior => "category_dropdown" },
                      :class => "form-select" %>
     </div>
+    <div class="mb-3 col-md">
+      <%= text_field_tag :username,
+                         params[:username],
+                         :placeholder => t(".name_or_email"),
+                         :autocomplete => "on",
+                         :class => "form-control" %>
+    </div>
     <div class="mb-3 col-md">
       <%= text_field_tag :ip,
                          params[:ip],
index e7b813b73f788fb7bf4cac947007c2ff0154340d..710e2c00950e9e6c568bec3e57238d775462b8aa 100644 (file)
@@ -30,5 +30,6 @@ Rails.application.config.middleware.insert_before 0, OpenStreetMap::Cors do
     resource "/diary/*/rss", :headers => :any, :methods => [:get]
     resource "/trace/*/data", :headers => :any, :methods => [:get]
     resource "/user/*/diary/rss", :headers => :any, :methods => [:get]
+    resource "/rails/active_storage/*", :headers => :any, :methods => [:get]
   end
 end
index f03a6eeb1f6ae418100d83b6c16aa4e8fae4be19..0deb199a38d034a4f8828891046ab418fa841674 100644 (file)
@@ -2897,6 +2897,7 @@ en:
           confirmed: Confirmed
           suspended: Suspended
           deleted: Deleted
+        name_or_email: Name or Email
         ip_address: IP Address
         search: Search
       page:
index 3029a418f824e38c1811b2cba90e8c413058ddce..7d200da867ac8512d4931f5e3f45a83b340d4a79 100644 (file)
@@ -18,19 +18,19 @@ OpenStreetMap::Application.routes.draw do
     get "permissions" => "permissions#show"
 
     post "changeset/:id/upload" => "changesets#upload", :as => :changeset_upload, :id => /\d+/
-    get "changeset/:id/download" => "changesets#download", :as => :changeset_download, :id => /\d+/
-    get "changeset/:id" => "changesets#show", :as => :changeset_show, :id => /\d+/
     post "changeset/:id/subscribe" => "changesets#subscribe", :as => :api_changeset_subscribe, :id => /\d+/
     post "changeset/:id/unsubscribe" => "changesets#unsubscribe", :as => :api_changeset_unsubscribe, :id => /\d+/
-    put "changeset/:id" => "changesets#update", :id => /\d+/
     put "changeset/:id/close" => "changesets#close", :as => :changeset_close, :id => /\d+/
-    post "changeset/:id/comment" => "changeset_comments#create", :as => :changeset_comment, :id => /\d+/
     post "changeset/comment/:id/hide" => "changeset_comments#destroy", :as => :changeset_comment_hide, :id => /\d+/
     post "changeset/comment/:id/unhide" => "changeset_comments#restore", :as => :changeset_comment_unhide, :id => /\d+/
   end
 
   namespace :api, :path => "api/0.6" do
     resources :changesets, :only => [:index, :create]
+    resources :changesets, :path => "changeset", :id => /\d+/, :only => [:show, :update] do
+      resource :download, :module => :changesets, :only => :show
+      resources :changeset_comments, :path => "comment", :only => :create
+    end
     put "changeset/create" => "changesets#create", :as => nil
 
     resources :changeset_comments, :only => :index
index 72463ed676e3ae39044e8473da70929260354909..2a386b3e5a2dee84f4a8dbe4bedf74cf67bfc9dc 100644 (file)
@@ -15,11 +15,11 @@ module Api
       )
       assert_routing(
         { :path => "/api/0.6/changeset/1/comment", :method => :post },
-        { :controller => "api/changeset_comments", :action => "create", :id => "1" }
+        { :controller => "api/changeset_comments", :action => "create", :changeset_id => "1" }
       )
       assert_routing(
         { :path => "/api/0.6/changeset/1/comment.json", :method => :post },
-        { :controller => "api/changeset_comments", :action => "create", :id => "1", :format => "json" }
+        { :controller => "api/changeset_comments", :action => "create", :changeset_id => "1", :format => "json" }
       )
       assert_routing(
         { :path => "/api/0.6/changeset/comment/1/hide", :method => :post },
@@ -81,35 +81,35 @@ module Api
 
     def test_create_by_unauthorized
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(create(:changeset, :closed), :text => "This is a comment")
+        post api_changeset_changeset_comments_path(create(:changeset, :closed), :text => "This is a comment")
         assert_response :unauthorized
       end
     end
 
     def test_create_on_missing_changeset
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(999111, :text => "This is a comment"), :headers => bearer_authorization_header
+        post api_changeset_changeset_comments_path(999111, :text => "This is a comment"), :headers => bearer_authorization_header
         assert_response :not_found
       end
     end
 
     def test_create_on_open_changeset
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(create(:changeset), :text => "This is a comment"), :headers => bearer_authorization_header
+        post api_changeset_changeset_comments_path(create(:changeset), :text => "This is a comment"), :headers => bearer_authorization_header
         assert_response :conflict
       end
     end
 
     def test_create_without_text
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(create(:changeset, :closed)), :headers => bearer_authorization_header
+        post api_changeset_changeset_comments_path(create(:changeset, :closed)), :headers => bearer_authorization_header
         assert_response :bad_request
       end
     end
 
     def test_create_with_empty_text
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(create(:changeset, :closed), :text => ""), :headers => bearer_authorization_header
+        post api_changeset_changeset_comments_path(create(:changeset, :closed), :text => ""), :headers => bearer_authorization_header
         assert_response :bad_request
       end
     end
@@ -120,7 +120,7 @@ module Api
       changeset = create(:changeset, :closed)
 
       assert_difference "ChangesetComment.count", 0 do
-        post changeset_comment_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
         assert_response :forbidden
       end
     end
@@ -131,7 +131,7 @@ module Api
       changeset = create(:changeset, :closed)
 
       assert_difference "ChangesetComment.count", 0 do
-        post changeset_comment_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
         assert_response :forbidden
       end
     end
@@ -142,7 +142,7 @@ module Api
       changeset = create(:changeset, :closed)
 
       assert_difference "ChangesetComment.count", 1 do
-        post changeset_comment_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
         assert_response :success
       end
 
@@ -159,7 +159,7 @@ module Api
       changeset = create(:changeset, :closed)
 
       assert_difference "ChangesetComment.count", 1 do
-        post changeset_comment_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset), :params => { :text => "This is a comment" }, :headers => auth_header
         assert_response :success
       end
 
@@ -177,7 +177,7 @@ module Api
       assert_difference "ChangesetComment.count", 1 do
         assert_no_difference "ActionMailer::Base.deliveries.size" do
           perform_enqueued_jobs do
-            post changeset_comment_path(changeset, :text => "This is a comment"), :headers => auth_header
+            post api_changeset_changeset_comments_path(changeset, :text => "This is a comment"), :headers => auth_header
             assert_response :success
           end
         end
@@ -193,7 +193,7 @@ module Api
       assert_difference "ChangesetComment.count", 1 do
         assert_no_difference "ActionMailer::Base.deliveries.size" do
           perform_enqueued_jobs do
-            post changeset_comment_path(changeset, :text => "This is a comment"), :headers => auth_header
+            post api_changeset_changeset_comments_path(changeset, :text => "This is a comment"), :headers => auth_header
             assert_response :success
           end
         end
@@ -209,7 +209,7 @@ module Api
       assert_difference "ChangesetComment.count", 1 do
         assert_no_difference "ActionMailer::Base.deliveries.size" do
           perform_enqueued_jobs do
-            post changeset_comment_path(changeset, :text => "This is a comment"), :headers => auth_header
+            post api_changeset_changeset_comments_path(changeset, :text => "This is a comment"), :headers => auth_header
             assert_response :success
           end
         end
@@ -226,7 +226,7 @@ module Api
       assert_difference "ChangesetComment.count", 1 do
         assert_difference "ActionMailer::Base.deliveries.size", 1 do
           perform_enqueued_jobs do
-            post changeset_comment_path(changeset, :text => "This is a comment"), :headers => auth_header
+            post api_changeset_changeset_comments_path(changeset, :text => "This is a comment"), :headers => auth_header
             assert_response :success
           end
         end
@@ -250,7 +250,7 @@ module Api
       assert_difference "ChangesetComment.count", 1 do
         assert_difference "ActionMailer::Base.deliveries.size", 2 do
           perform_enqueued_jobs do
-            post changeset_comment_path(changeset, :text => "This is a comment"), :headers => auth_header
+            post api_changeset_changeset_comments_path(changeset, :text => "This is a comment"), :headers => auth_header
             assert_response :success
           end
         end
@@ -277,13 +277,13 @@ module Api
 
       assert_difference "ChangesetComment.count", Settings.initial_changeset_comments_per_hour do
         1.upto(Settings.initial_changeset_comments_per_hour) do |count|
-          post changeset_comment_path(changeset, :text => "Comment #{count}"), :headers => auth_header
+          post api_changeset_changeset_comments_path(changeset, :text => "Comment #{count}"), :headers => auth_header
           assert_response :success
         end
       end
 
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(changeset, :text => "One comment too many"), :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset, :text => "One comment too many"), :headers => auth_header
         assert_response :too_many_requests
       end
     end
@@ -299,13 +299,13 @@ module Api
 
       assert_difference "ChangesetComment.count", Settings.max_changeset_comments_per_hour do
         1.upto(Settings.max_changeset_comments_per_hour) do |count|
-          post changeset_comment_path(changeset, :text => "Comment #{count}"), :headers => auth_header
+          post api_changeset_changeset_comments_path(changeset, :text => "Comment #{count}"), :headers => auth_header
           assert_response :success
         end
       end
 
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(changeset, :text => "One comment too many"), :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset, :text => "One comment too many"), :headers => auth_header
         assert_response :too_many_requests
       end
     end
@@ -321,13 +321,13 @@ module Api
 
       assert_difference "ChangesetComment.count", Settings.initial_changeset_comments_per_hour / 2 do
         1.upto(Settings.initial_changeset_comments_per_hour / 2) do |count|
-          post changeset_comment_path(changeset, :text => "Comment #{count}"), :headers => auth_header
+          post api_changeset_changeset_comments_path(changeset, :text => "Comment #{count}"), :headers => auth_header
           assert_response :success
         end
       end
 
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(changeset, :text => "One comment too many"), :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset, :text => "One comment too many"), :headers => auth_header
         assert_response :too_many_requests
       end
     end
@@ -342,13 +342,13 @@ module Api
 
       assert_difference "ChangesetComment.count", Settings.moderator_changeset_comments_per_hour do
         1.upto(Settings.moderator_changeset_comments_per_hour) do |count|
-          post changeset_comment_path(changeset, :text => "Comment #{count}"), :headers => auth_header
+          post api_changeset_changeset_comments_path(changeset, :text => "Comment #{count}"), :headers => auth_header
           assert_response :success
         end
       end
 
       assert_no_difference "ChangesetComment.count" do
-        post changeset_comment_path(changeset, :text => "One comment too many"), :headers => auth_header
+        post api_changeset_changeset_comments_path(changeset, :text => "One comment too many"), :headers => auth_header
         assert_response :too_many_requests
       end
     end
diff --git a/test/controllers/api/changesets/downloads_controller_test.rb b/test/controllers/api/changesets/downloads_controller_test.rb
new file mode 100644 (file)
index 0000000..9eda6ec
--- /dev/null
@@ -0,0 +1,309 @@
+require "test_helper"
+
+module Api
+  module Changesets
+    class DownloadsControllerTest < ActionDispatch::IntegrationTest
+      ##
+      # test all routes which lead to this controller
+      def test_routes
+        assert_routing(
+          { :path => "/api/0.6/changeset/1/download", :method => :get },
+          { :controller => "api/changesets/downloads", :action => "show", :changeset_id => "1" }
+        )
+      end
+
+      def test_show_empty
+        changeset = create(:changeset)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
+          assert_dom "create", 0
+          assert_dom "modify", 0
+          assert_dom "delete", 0
+        end
+      end
+
+      def test_show_created_elements
+        changeset = create(:changeset)
+        old_node1 = create(:old_node, :changeset => changeset, :version => 1, :latitude => (60.12345 * OldNode::SCALE).to_i, :longitude => (30.54321 * OldNode::SCALE).to_i)
+        create(:old_node_tag, :old_node => old_node1, :k => "highway", :v => "crossing")
+        create(:old_node_tag, :old_node => old_node1, :k => "crossing", :v => "marked")
+        old_node2 = create(:old_node, :changeset => changeset, :version => 1, :latitude => (60.23456 * OldNode::SCALE).to_i, :longitude => (30.65432 * OldNode::SCALE).to_i)
+        create(:old_node_tag, :old_node => old_node2, :k => "highway", :v => "traffic_signals")
+        old_way = create(:old_way, :changeset => changeset, :version => 1)
+        create(:old_way_tag, :old_way => old_way, :k => "highway", :v => "secondary")
+        create(:old_way_tag, :old_way => old_way, :k => "name", :v => "Some Street")
+        create(:old_way_node, :old_way => old_way, :node => old_node1.current_node, :sequence_id => 1)
+        create(:old_way_node, :old_way => old_way, :node => old_node2.current_node, :sequence_id => 2)
+        old_relation = create(:old_relation, :changeset => changeset, :version => 1)
+        create(:old_relation_tag, :old_relation => old_relation, :k => "type", :v => "restriction")
+        create(:old_relation_member, :old_relation => old_relation, :member => old_way.current_way, :member_role => "from", :sequence_id => 1)
+        create(:old_relation_member, :old_relation => old_relation, :member => old_node2.current_node, :member_role => "via", :sequence_id => 2)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
+          assert_dom "create", 4 do
+            assert_dom "node", 2
+            assert_dom "node[id='#{old_node1.node_id}']", 1 do
+              assert_dom "> @version", "1"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 2
+              assert_dom "tag[k='highway'][v='crossing']"
+              assert_dom "tag[k='crossing'][v='marked']"
+              assert_dom "> @lat", "60.1234500"
+              assert_dom "> @lon", "30.5432100"
+            end
+            assert_dom "node[id='#{old_node2.node_id}']", 1 do
+              assert_dom "> @version", "1"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 1
+              assert_dom "tag[k='highway'][v='traffic_signals']"
+              assert_dom "> @lat", "60.2345600"
+              assert_dom "> @lon", "30.6543200"
+            end
+            assert_dom "way", 1
+            assert_dom "way[id='#{old_way.way_id}']", 1 do
+              assert_dom "> @version", "1"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 2
+              assert_dom "tag[k='highway'][v='secondary']"
+              assert_dom "tag[k='name'][v='Some Street']"
+              assert_dom "nd", 2 do |dom_nds|
+                assert_dom dom_nds[0], "> @ref", old_node1.node_id.to_s
+                assert_dom dom_nds[1], "> @ref", old_node2.node_id.to_s
+              end
+            end
+            assert_dom "relation", 1
+            assert_dom "relation[id='#{old_relation.relation_id}']", 1 do
+              assert_dom "> @version", "1"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 1
+              assert_dom "tag[k='type'][v='restriction']"
+              assert_dom "member", 2 do |dom_members|
+                assert_dom dom_members[0], "> @type", "way"
+                assert_dom dom_members[0], "> @ref", old_way.way_id.to_s
+                assert_dom dom_members[0], "> @role", "from"
+                assert_dom dom_members[1], "> @type", "node"
+                assert_dom dom_members[1], "> @ref", old_node2.node_id.to_s
+                assert_dom dom_members[1], "> @role", "via"
+              end
+            end
+          end
+        end
+      end
+
+      def test_show_edited_elements
+        changeset = create(:changeset)
+        old_node1 = create(:old_node, :changeset => changeset, :version => 2, :latitude => (60.12345 * OldNode::SCALE).to_i, :longitude => (30.54321 * OldNode::SCALE).to_i)
+        create(:old_node_tag, :old_node => old_node1, :k => "highway", :v => "crossing")
+        create(:old_node_tag, :old_node => old_node1, :k => "crossing", :v => "marked")
+        old_node2 = create(:old_node, :changeset => changeset, :version => 2, :latitude => (60.23456 * OldNode::SCALE).to_i, :longitude => (30.65432 * OldNode::SCALE).to_i)
+        create(:old_node_tag, :old_node => old_node2, :k => "highway", :v => "traffic_signals")
+        old_way = create(:old_way, :changeset => changeset, :version => 2)
+        create(:old_way_tag, :old_way => old_way, :k => "highway", :v => "secondary")
+        create(:old_way_tag, :old_way => old_way, :k => "name", :v => "Some Street")
+        create(:old_way_node, :old_way => old_way, :node => old_node1.current_node, :sequence_id => 1)
+        create(:old_way_node, :old_way => old_way, :node => old_node2.current_node, :sequence_id => 2)
+        old_relation = create(:old_relation, :changeset => changeset, :version => 2)
+        create(:old_relation_tag, :old_relation => old_relation, :k => "type", :v => "restriction")
+        create(:old_relation_member, :old_relation => old_relation, :member => old_way.current_way, :member_role => "from", :sequence_id => 1)
+        create(:old_relation_member, :old_relation => old_relation, :member => old_node2.current_node, :member_role => "via", :sequence_id => 2)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
+          assert_dom "modify", 4 do
+            assert_dom "node", 2
+            assert_dom "node[id='#{old_node1.node_id}']", 1 do
+              assert_dom "> @version", "2"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 2
+              assert_dom "tag[k='highway'][v='crossing']"
+              assert_dom "tag[k='crossing'][v='marked']"
+              assert_dom "> @lat", "60.1234500"
+              assert_dom "> @lon", "30.5432100"
+            end
+            assert_dom "node[id='#{old_node2.node_id}']", 1 do
+              assert_dom "> @version", "2"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 1
+              assert_dom "tag[k='highway'][v='traffic_signals']"
+              assert_dom "> @lat", "60.2345600"
+              assert_dom "> @lon", "30.6543200"
+            end
+            assert_dom "way", 1
+            assert_dom "way[id='#{old_way.way_id}']", 1 do
+              assert_dom "> @version", "2"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 2
+              assert_dom "tag[k='highway'][v='secondary']"
+              assert_dom "tag[k='name'][v='Some Street']"
+              assert_dom "nd", 2 do |dom_nds|
+                assert_dom dom_nds[0], "> @ref", old_node1.node_id.to_s
+                assert_dom dom_nds[1], "> @ref", old_node2.node_id.to_s
+              end
+            end
+            assert_dom "relation", 1
+            assert_dom "relation[id='#{old_relation.relation_id}']", 1 do
+              assert_dom "> @version", "2"
+              assert_dom "> @visible", "true"
+              assert_dom "tag", 1
+              assert_dom "tag[k='type'][v='restriction']"
+              assert_dom "member", 2 do |dom_members|
+                assert_dom dom_members[0], "> @type", "way"
+                assert_dom dom_members[0], "> @ref", old_way.way_id.to_s
+                assert_dom dom_members[0], "> @role", "from"
+                assert_dom dom_members[1], "> @type", "node"
+                assert_dom dom_members[1], "> @ref", old_node2.node_id.to_s
+                assert_dom dom_members[1], "> @role", "via"
+              end
+            end
+          end
+        end
+      end
+
+      def test_show_deleted_elements
+        changeset = create(:changeset)
+        old_node1 = create(:old_node, :changeset => changeset, :version => 3, :visible => false)
+        old_node2 = create(:old_node, :changeset => changeset, :version => 3, :visible => false)
+        old_way = create(:old_way, :changeset => changeset, :version => 3, :visible => false)
+        old_relation = create(:old_relation, :changeset => changeset, :version => 3, :visible => false)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
+          assert_dom "delete", 4 do
+            assert_dom "node", 2
+            assert_dom "node[id='#{old_node1.node_id}']", 1 do
+              assert_dom "> @version", "3"
+              assert_dom "> @visible", "false"
+            end
+            assert_dom "node[id='#{old_node2.node_id}']", 1 do
+              assert_dom "> @version", "3"
+              assert_dom "> @visible", "false"
+            end
+            assert_dom "way", 1
+            assert_dom "way[id='#{old_way.way_id}']", 1 do
+              assert_dom "> @version", "3"
+              assert_dom "> @visible", "false"
+            end
+            assert_dom "relation", 1
+            assert_dom "relation[id='#{old_relation.relation_id}']", 1 do
+              assert_dom "> @version", "3"
+              assert_dom "> @visible", "false"
+            end
+          end
+        end
+      end
+
+      def test_show_should_sort_by_timestamp
+        changeset = create(:changeset)
+        node1 = create(:old_node, :version => 2, :timestamp => "2020-02-01", :changeset => changeset)
+        node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "modify", :count => 2 do |modify|
+          assert_dom modify[0], ">node", :count => 1 do |node|
+            assert_dom node, ">@id", node0.node_id.to_s
+          end
+          assert_dom modify[1], ">node", :count => 1 do |node|
+            assert_dom node, ">@id", node1.node_id.to_s
+          end
+        end
+      end
+
+      def test_show_should_sort_by_version
+        changeset = create(:changeset)
+        node1 = create(:old_node, :version => 3, :timestamp => "2020-01-01", :changeset => changeset)
+        node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
+
+        get api_changeset_download_path(changeset)
+
+        assert_response :success
+        assert_dom "modify", :count => 2 do |modify|
+          assert_dom modify[0], ">node", :count => 1 do |node|
+            assert_dom node, ">@id", node0.node_id.to_s
+          end
+          assert_dom modify[1], ">node", :count => 1 do |node|
+            assert_dom node, ">@id", node1.node_id.to_s
+          end
+        end
+      end
+
+      ##
+      # check that the changeset download for a changeset with a redacted
+      # element in it doesn't contain that element.
+      def test_show_redacted
+        check_redacted do |changeset|
+          get api_changeset_download_path(changeset)
+        end
+      end
+
+      def test_show_redacted_unauthorized
+        check_redacted do |changeset|
+          get api_changeset_download_path(changeset, :show_redactions => "true")
+        end
+      end
+
+      def test_show_redacted_normal_user
+        auth_header = bearer_authorization_header
+
+        check_redacted do |changeset|
+          get api_changeset_download_path(changeset, :show_redactions => "true"), :headers => auth_header
+        end
+      end
+
+      def test_show_redacted_moderator_without_show_redactions
+        auth_header = bearer_authorization_header create(:moderator_user)
+
+        check_redacted do |changeset|
+          get api_changeset_download_path(changeset), :headers => auth_header
+        end
+      end
+
+      def test_show_redacted_moderator
+        auth_header = bearer_authorization_header create(:moderator_user)
+
+        check_redacted(:redacted_included => true) do |changeset|
+          get api_changeset_download_path(changeset, :show_redactions => "true"), :headers => auth_header
+        end
+      end
+
+      private
+
+      def check_redacted(redacted_included: false)
+        redaction = create(:redaction)
+        changeset = create(:changeset)
+        node = create(:node, :with_history, :version => 2, :changeset => changeset)
+        node_v1 = node.old_nodes.find_by(:version => 1)
+        node_v1.redact!(redaction)
+        way = create(:way, :with_history, :version => 2, :changeset => changeset)
+        way_v1 = way.old_ways.find_by(:version => 1)
+        way_v1.redact!(redaction)
+        relation = create(:relation, :with_history, :version => 2, :changeset => changeset)
+        relation_v1 = relation.old_relations.find_by(:version => 1)
+        relation_v1.redact!(redaction)
+
+        yield changeset
+
+        assert_response :success
+        assert_dom "osmChange", 1 do
+          assert_dom "node[id='#{node.id}'][version='1']", redacted_included ? 1 : 0
+          assert_dom "node[id='#{node.id}'][version='2']", 1
+          assert_dom "way[id='#{way.id}'][version='1']", redacted_included ? 1 : 0
+          assert_dom "way[id='#{way.id}'][version='2']", 1
+          assert_dom "relation[id='#{relation.id}'][version='1']", redacted_included ? 1 : 0
+          assert_dom "relation[id='#{relation.id}'][version='2']", 1
+        end
+      end
+    end
+  end
+end
index e73459a36d0693a64c897e0c76054ea2eb92737d..87deb3bdfcb2c1b064eb8b7be3ed8c4fd5b9836b 100644 (file)
@@ -17,14 +17,6 @@ module Api
         { :path => "/api/0.6/changesets", :method => :post },
         { :controller => "api/changesets", :action => "create" }
       )
-      assert_routing(
-        { :path => "/api/0.6/changeset/1/upload", :method => :post },
-        { :controller => "api/changesets", :action => "upload", :id => "1" }
-      )
-      assert_routing(
-        { :path => "/api/0.6/changeset/1/download", :method => :get },
-        { :controller => "api/changesets", :action => "download", :id => "1" }
-      )
       assert_routing(
         { :path => "/api/0.6/changeset/1", :method => :get },
         { :controller => "api/changesets", :action => "show", :id => "1" }
@@ -33,6 +25,14 @@ module Api
         { :path => "/api/0.6/changeset/1.json", :method => :get },
         { :controller => "api/changesets", :action => "show", :id => "1", :format => "json" }
       )
+      assert_routing(
+        { :path => "/api/0.6/changeset/1", :method => :put },
+        { :controller => "api/changesets", :action => "update", :id => "1" }
+      )
+      assert_routing(
+        { :path => "/api/0.6/changeset/1/upload", :method => :post },
+        { :controller => "api/changesets", :action => "upload", :id => "1" }
+      )
       assert_routing(
         { :path => "/api/0.6/changeset/1/subscribe", :method => :post },
         { :controller => "api/changesets", :action => "subscribe", :id => "1" }
@@ -49,10 +49,6 @@ module Api
         { :path => "/api/0.6/changeset/1/unsubscribe.json", :method => :post },
         { :controller => "api/changesets", :action => "unsubscribe", :id => "1", :format => "json" }
       )
-      assert_routing(
-        { :path => "/api/0.6/changeset/1", :method => :put },
-        { :controller => "api/changesets", :action => "update", :id => "1" }
-      )
       assert_routing(
         { :path => "/api/0.6/changeset/1/close", :method => :put },
         { :controller => "api/changesets", :action => "close", :id => "1" }
@@ -406,7 +402,7 @@ module Api
     def test_show
       changeset = create(:changeset)
 
-      get changeset_show_path(changeset)
+      get api_changeset_path(changeset)
       assert_response :success, "cannot get first changeset"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -414,7 +410,7 @@ module Api
         assert_dom "> discussion", 0
       end
 
-      get changeset_show_path(changeset), :params => { :include_discussion => true }
+      get api_changeset_path(changeset, :include_discussion => true)
       assert_response :success, "cannot get first changeset with comments"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -429,7 +425,7 @@ module Api
       changeset = create(:changeset, :closed)
       comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
-      get changeset_show_path(changeset), :params => { :include_discussion => true }
+      get api_changeset_path(changeset, :include_discussion => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
@@ -451,7 +447,7 @@ module Api
       comment2.update(:visible => false)
       changeset.reload
 
-      get changeset_show_path(changeset), :params => { :include_discussion => true }
+      get api_changeset_path(changeset, :include_discussion => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -467,7 +463,7 @@ module Api
       end
 
       # one hidden comment not included because no permissions
-      get changeset_show_path(changeset), :params => { :include_discussion => true, :show_hidden_comments => true }
+      get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -486,8 +482,7 @@ module Api
       # one hidden comment shown to moderators
       moderator_user = create(:moderator_user)
       auth_header = bearer_authorization_header moderator_user
-      get changeset_show_path(changeset), :params => { :include_discussion => true, :show_hidden_comments => true },
-                                          :headers => auth_header
+      get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
       assert_response :success, "cannot get closed changeset with comments"
 
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -510,7 +505,7 @@ module Api
       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
 
-      get changeset_show_path(changeset)
+      get api_changeset_path(changeset)
 
       assert_response :success
       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
@@ -524,7 +519,7 @@ module Api
     def test_show_json
       changeset = create(:changeset)
 
-      get changeset_show_path(changeset), :params => { :format => "json" }
+      get api_changeset_path(changeset, :format => "json")
       assert_response :success, "cannot get first changeset"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -538,7 +533,7 @@ module Api
       assert_equal changeset.user.id, js["changeset"]["uid"]
       assert_equal changeset.user.display_name, js["changeset"]["user"]
 
-      get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
+      get api_changeset_path(changeset, :format => "json", :include_discussion => true)
       assert_response :success, "cannot get first changeset with comments"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -559,7 +554,7 @@ module Api
       changeset = create(:changeset, :closed)
       comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
-      get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
+      get api_changeset_path(changeset, :format => "json", :include_discussion => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -579,7 +574,7 @@ module Api
       comment1.update(:visible => false)
       changeset.reload
 
-      get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
+      get api_changeset_path(changeset, :format => "json", :include_discussion => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -594,7 +589,7 @@ module Api
       assert js["changeset"]["comments"][1]["visible"]
 
       # one hidden comment not included because no permissions
-      get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true, :show_hidden_comments => true }
+      get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true)
       assert_response :success, "cannot get closed changeset with comments"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -612,8 +607,7 @@ module Api
       # one hidden comment shown to moderators
       moderator_user = create(:moderator_user)
       auth_header = bearer_authorization_header moderator_user
-      get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true, :show_hidden_comments => true },
-                                          :headers => auth_header
+      get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
       assert_response :success, "cannot get closed changeset with comments"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -635,7 +629,7 @@ module Api
       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
 
-      get changeset_show_path(changeset, :format => "json")
+      get api_changeset_path(changeset, :format => "json")
 
       assert_response :success
       js = ActiveSupport::JSON.decode(@response.body)
@@ -653,7 +647,7 @@ module Api
       changeset = create(:changeset, :min_lat => (-5 * GeoRecord::SCALE).round, :min_lon => (5 * GeoRecord::SCALE).round,
                                      :max_lat => (15 * GeoRecord::SCALE).round, :max_lon => (12 * GeoRecord::SCALE).round)
 
-      get changeset_show_path(changeset), :params => { :format => "json" }
+      get api_changeset_path(changeset, :format => "json")
       assert_response :success, "cannot get first changeset"
 
       js = ActiveSupport::JSON.decode(@response.body)
@@ -668,7 +662,7 @@ module Api
     # check that a changeset that doesn't exist returns an appropriate message
     def test_show_not_found
       [0, -32, 233455644, "afg", "213"].each do |id|
-        get changeset_show_path(id)
+        get api_changeset_path(id)
         assert_response :not_found, "should get a not found"
       rescue ActionController::UrlGenerationError => e
         assert_match(/No route matches/, e.to_s)
@@ -2186,7 +2180,7 @@ module Api
       assert_response :success,
                       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
-      get changeset_download_path(changeset_id)
+      get api_changeset_download_path(changeset_id)
       assert_response :success
 
       assert_select "osmChange", 1
@@ -2244,7 +2238,7 @@ module Api
       assert_response :success,
                       "can't upload a diff from JOSM: #{@response.body}"
 
-      get changeset_download_path(changeset_id)
+      get api_changeset_download_path(changeset_id)
       assert_response :success
 
       assert_select "osmChange", 1
@@ -2299,7 +2293,7 @@ module Api
       assert_response :success,
                       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
-      get changeset_download_path(changeset_id)
+      get api_changeset_download_path(changeset_id)
       assert_response :success
 
       assert_select "osmChange", 1
@@ -2312,63 +2306,6 @@ module Api
       assert_select "osmChange>modify>way", 1
     end
 
-    def test_changeset_download
-      changeset = create(:changeset)
-      node = create(:node, :with_history, :version => 1, :changeset => changeset)
-      tag = create(:old_node_tag, :old_node => node.old_nodes.find_by(:version => 1))
-      node2 = create(:node, :with_history, :version => 1, :changeset => changeset)
-      _node3 = create(:node, :with_history, :deleted, :version => 1, :changeset => changeset)
-      _relation = create(:relation, :with_history, :version => 1, :changeset => changeset)
-      _relation2 = create(:relation, :with_history, :deleted, :version => 1, :changeset => changeset)
-
-      get changeset_download_path(changeset)
-
-      assert_response :success
-
-      # FIXME: needs more assert_select tests
-      assert_select "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
-        assert_select "create", :count => 5
-        assert_select "create>node[id='#{node.id}'][visible='#{node.visible?}'][version='#{node.version}']" do
-          assert_select "tag[k='#{tag.k}'][v='#{tag.v}']"
-        end
-        assert_select "create>node[id='#{node2.id}']"
-      end
-    end
-
-    test "sorts downloaded elements by timestamp" do
-      changeset = create(:changeset)
-      node1 = create(:old_node, :version => 2, :timestamp => "2020-02-01", :changeset => changeset)
-      node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
-
-      get changeset_download_path(changeset)
-      assert_response :success
-      assert_dom "modify", :count => 2 do |modify|
-        assert_dom modify[0], ">node", :count => 1 do |node|
-          assert_dom node, ">@id", node0.node_id.to_s
-        end
-        assert_dom modify[1], ">node", :count => 1 do |node|
-          assert_dom node, ">@id", node1.node_id.to_s
-        end
-      end
-    end
-
-    test "sorts downloaded elements by version" do
-      changeset = create(:changeset)
-      node1 = create(:old_node, :version => 3, :timestamp => "2020-01-01", :changeset => changeset)
-      node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
-
-      get changeset_download_path(changeset)
-      assert_response :success
-      assert_dom "modify", :count => 2 do |modify|
-        assert_dom modify[0], ">node", :count => 1 do |node|
-          assert_dom node, ">@id", node0.node_id.to_s
-        end
-        assert_dom modify[1], ">node", :count => 1 do |node|
-          assert_dom node, ">@id", node1.node_id.to_s
-        end
-      end
-    end
-
     ##
     # check that the bounding box of a changeset gets updated correctly
     # FIXME: This should really be moded to a integration test due to the with_controller
@@ -2392,7 +2329,7 @@ module Api
       end
 
       # get the bounding box back from the changeset
-      get changeset_show_path(changeset_id)
+      get api_changeset_path(changeset_id)
       assert_response :success, "Couldn't read back changeset."
       assert_select "osm>changeset[min_lon='0.1000000']", 1
       assert_select "osm>changeset[max_lon='0.1000000']", 1
@@ -2407,7 +2344,7 @@ module Api
       end
 
       # get the bounding box back from the changeset
-      get changeset_show_path(changeset_id)
+      get api_changeset_path(changeset_id)
       assert_response :success, "Couldn't read back changeset for the second time."
       assert_select "osm>changeset[min_lon='0.1000000']", 1
       assert_select "osm>changeset[max_lon='0.2000000']", 1
@@ -2422,7 +2359,7 @@ module Api
       end
 
       # get the bounding box back from the changeset
-      get changeset_show_path(changeset_id)
+      get api_changeset_path(changeset_id)
       assert_response :success, "Couldn't read back changeset for the third time."
       assert_select "osm>changeset[min_lon='0.1000000']", 1
       assert_select "osm>changeset[max_lon='0.3000000']", 1
@@ -2446,17 +2383,17 @@ module Api
       new_changeset.find("//osm/changeset").first << new_tag
 
       # try without any authorization
-      put changeset_show_path(private_changeset), :params => new_changeset.to_s
+      put api_changeset_path(private_changeset), :params => new_changeset.to_s
       assert_response :unauthorized
 
       # try with the wrong authorization
       auth_header = bearer_authorization_header
-      put changeset_show_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
+      put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
       assert_response :conflict
 
       # now this should get an unauthorized
       auth_header = bearer_authorization_header private_user
-      put changeset_show_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
+      put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
       assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
 
       ## Now try with the public user
@@ -2467,17 +2404,17 @@ module Api
       new_changeset.find("//osm/changeset").first << new_tag
 
       # try without any authorization
-      put changeset_show_path(changeset), :params => new_changeset.to_s
+      put api_changeset_path(changeset), :params => new_changeset.to_s
       assert_response :unauthorized
 
       # try with the wrong authorization
       auth_header = bearer_authorization_header
-      put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
+      put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
       assert_response :conflict
 
       # now this should work...
       auth_header = bearer_authorization_header user
-      put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
+      put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
       assert_response :success
 
       assert_select "osm>changeset[id='#{changeset.id}']", 1
@@ -2498,7 +2435,7 @@ module Api
       new_tag["v"] = "testing"
       new_changeset.find("//osm/changeset").first << new_tag
 
-      put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
+      put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
       assert_response :conflict
     end
 
@@ -2566,25 +2503,6 @@ module Api
                  "element limit.")
     end
 
-    ##
-    # check that the changeset download for a changeset with a redacted
-    # element in it doesn't contain that element.
-    def test_diff_download_redacted
-      changeset = create(:changeset)
-      node = create(:node, :with_history, :version => 2, :changeset => changeset)
-      node_v1 = node.old_nodes.find_by(:version => 1)
-      node_v1.redact!(create(:redaction))
-
-      get changeset_download_path(changeset)
-      assert_response :success
-
-      assert_select "osmChange", 1
-      # this changeset contains the node in versions 1 & 2, but 1 should
-      # be hidden.
-      assert_select "osmChange node[id='#{node.id}']", 1
-      assert_select "osmChange node[id='#{node.id}'][version='1']", 0
-    end
-
     ##
     # test subscribe success
     def test_subscribe_success
index f585c5c2cf6dda76c32d2a73e34890f941715d2e..a4c8522e82f081be9f99f9bda034cd31106fb9b1 100644 (file)
@@ -1064,7 +1064,7 @@ module Api
 
       # now download the changeset to check its bounding box
       with_controller(Api::ChangesetsController.new) do
-        get changeset_show_path(changeset_id)
+        get api_changeset_path(changeset_id)
         assert_response :success, "can't re-read changeset for modify test"
         assert_select "osm>changeset", 1, "Changeset element doesn't exist in #{@response.body}"
         assert_select "osm>changeset[id='#{changeset_id}']", 1, "Changeset id=#{changeset_id} doesn't exist in #{@response.body}"
index b683107d9a61b30fe257728d74bebbff413fbc32..724c43222b61a84869a1f7787919b8c45153c623 100644 (file)
@@ -27,12 +27,14 @@ module Users
       user = create(:user)
       moderator_user = create(:moderator_user)
       administrator_user = create(:administrator_user)
-      _suspended_user = create(:user, :suspended)
-      _ip_user = create(:user, :creation_address => "1.2.3.4")
+      suspended_user = create(:user, :suspended)
+      name_user = create(:user, :display_name => "Test User")
+      email_user = create(:user, :email => "test@example.com")
+      ip_user = create(:user, :creation_address => "1.2.3.4")
 
-      # There are now 7 users - the five above, plus two extra "granters" for the
+      # There are now 9 users - the 7 above, plus two extra "granters" for the
       # moderator_user and administrator_user
-      assert_equal 7, User.count
+      assert_equal 9, User.count
 
       # Shouldn't work when not logged in
       get users_list_path
@@ -57,19 +59,55 @@ module Users
       get users_list_path
       assert_response :success
       assert_template :show
-      assert_select "table#user_list tbody tr", :count => 7
+      assert_select "table#user_list tbody tr", :count => 9
 
       # Should be able to limit by status
       get users_list_path, :params => { :status => "suspended" }
       assert_response :success
       assert_template :show
-      assert_select "table#user_list tbody tr", :count => 1
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(suspended_user)}']", :count => 1
+      end
+
+      # Should be able to limit by name
+      get users_list_path, :params => { :username => "Test User" }
+      assert_response :success
+      assert_template :show
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(name_user)}']", :count => 1
+      end
+
+      # Should be able to limit by name ignoring case
+      get users_list_path, :params => { :username => "test user" }
+      assert_response :success
+      assert_template :show
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(name_user)}']", :count => 1
+      end
+
+      # Should be able to limit by email
+      get users_list_path, :params => { :username => "test@example.com" }
+      assert_response :success
+      assert_template :show
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(email_user)}']", :count => 1
+      end
+
+      # Should be able to limit by email ignoring case
+      get users_list_path, :params => { :username => "TEST@example.com" }
+      assert_response :success
+      assert_template :show
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(email_user)}']", :count => 1
+      end
 
       # Should be able to limit by IP address
       get users_list_path, :params => { :ip => "1.2.3.4" }
       assert_response :success
       assert_template :show
-      assert_select "table#user_list tbody tr", :count => 1
+      assert_select "table#user_list tbody tr", :count => 1 do
+        assert_select "a[href='#{user_path(ip_user)}']", :count => 1
+      end
     end
 
     def test_show_paginated
index 71a706e4590dd048c5a612aa0eeb4454abe80f96..b4b8f2828c8959a5feb5fc524f92e6646ad0f125 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
   resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
   integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
 
-"@eslint/config-array@^0.19.0":
-  version "0.19.0"
-  resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.0.tgz#3251a528998de914d59bb21ba4c11767cf1b3519"
-  integrity sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==
+"@eslint/config-array@^0.19.2":
+  version "0.19.2"
+  resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa"
+  integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==
   dependencies:
-    "@eslint/object-schema" "^2.1.4"
+    "@eslint/object-schema" "^2.1.6"
     debug "^4.3.1"
     minimatch "^3.1.2"
 
-"@eslint/core@^0.10.0":
-  version "0.10.0"
-  resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091"
-  integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==
+"@eslint/core@^0.12.0":
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e"
+  integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==
   dependencies:
     "@types/json-schema" "^7.0.15"
 
-"@eslint/core@^0.11.0":
-  version "0.11.0"
-  resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12"
-  integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==
-  dependencies:
-    "@types/json-schema" "^7.0.15"
-
-"@eslint/eslintrc@^3.2.0":
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
-  integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
+"@eslint/eslintrc@^3.3.0":
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846"
+  integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==
   dependencies:
     ajv "^6.12.4"
     debug "^4.3.2"
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/js@9.20.0":
-  version "9.20.0"
-  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4"
-  integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==
+"@eslint/js@9.21.0":
+  version "9.21.0"
+  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08"
+  integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==
 
-"@eslint/object-schema@^2.1.4":
-  version "2.1.4"
-  resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843"
-  integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
+"@eslint/object-schema@^2.1.6":
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
+  integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
 
-"@eslint/plugin-kit@^0.2.5":
-  version "0.2.5"
-  resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81"
-  integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==
+"@eslint/plugin-kit@^0.2.7":
+  version "0.2.7"
+  resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27"
+  integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==
   dependencies:
-    "@eslint/core" "^0.10.0"
+    "@eslint/core" "^0.12.0"
     levn "^0.4.1"
 
 "@humanfs/core@^0.19.1":
   resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
   integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
 
-"@humanwhocodes/retry@^0.4.1":
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
-  integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
+"@humanwhocodes/retry@^0.4.2":
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161"
+  integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==
 
 "@stylistic/eslint-plugin-js@^4.0.0":
   version "4.0.1"
@@ -280,20 +273,20 @@ eslint-visitor-keys@^4.2.0:
   integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
 
 eslint@^9.0.0:
-  version "9.20.1"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6"
-  integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==
+  version "9.21.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591"
+  integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==
   dependencies:
     "@eslint-community/eslint-utils" "^4.2.0"
     "@eslint-community/regexpp" "^4.12.1"
-    "@eslint/config-array" "^0.19.0"
-    "@eslint/core" "^0.11.0"
-    "@eslint/eslintrc" "^3.2.0"
-    "@eslint/js" "9.20.0"
-    "@eslint/plugin-kit" "^0.2.5"
+    "@eslint/config-array" "^0.19.2"
+    "@eslint/core" "^0.12.0"
+    "@eslint/eslintrc" "^3.3.0"
+    "@eslint/js" "9.21.0"
+    "@eslint/plugin-kit" "^0.2.7"
     "@humanfs/node" "^0.16.6"
     "@humanwhocodes/module-importer" "^1.0.1"
-    "@humanwhocodes/retry" "^0.4.1"
+    "@humanwhocodes/retry" "^0.4.2"
     "@types/estree" "^1.0.6"
     "@types/json-schema" "^7.0.15"
     ajv "^6.12.4"