From: Tom Hughes Date: Thu, 27 Feb 2025 20:28:47 +0000 (+0000) Subject: Merge remote-tracking branch 'upstream/pull/5652' X-Git-Tag: live~4 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/ca4a2d9e9a3bdf214c6ec26ca9744aab4960a25a?hp=459d3b314a900b3fb83eb88502bb29e1c961082e Merge remote-tracking branch 'upstream/pull/5652' --- diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 66c2aca51..8c6680bdc 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -19,7 +19,7 @@ jobs: - name: Setup ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 3.1 + ruby-version: 3.2 rubygems: 3.4.10 bundler-cache: true - name: Create base branch diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8383068b3..433b523f7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,7 +6,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} cancel-in-progress: true env: - ruby: '3.1' + ruby: '3.2' jobs: rubocop: name: RuboCop diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d1cf73eae..841155bf6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ jobs: name: Ruby ${{ matrix.ruby }} strategy: matrix: - ruby: ['3.1', '3.2', '3.3', '3.4'] + ruby: ['3.2', '3.3', '3.4'] runs-on: ubuntu-latest env: RAILS_ENV: test diff --git a/.rubocop.yml b/.rubocop.yml index eedbf47e0..64a8d0a0f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,7 +12,7 @@ require: - ./.rubocop/specific_action_names.rb AllCops: - TargetRubyVersion: 3.1 + TargetRubyVersion: 3.2 NewCops: enable Exclude: - 'vendor/**/*' @@ -108,6 +108,10 @@ Style/MixinUsage: - 'bin/setup' - 'bin/update' +Style/RaiseArgs: + Exclude: + - 'lib/osm.rb' + Style/StringLiterals: EnforcedStyle: double_quotes @@ -129,7 +133,6 @@ Rails/SpecificActionNames: - app/controllers/**/*.rb Exclude: # This is a todo list, but is currently too long for `rubocop --auto-gen-config` - - 'app/controllers/api/changeset_comments_controller.rb' - 'app/controllers/api/changesets_controller.rb' - 'app/controllers/api/notes_controller.rb' - 'app/controllers/api/user_preferences_controller.rb' diff --git a/Dockerfile b/Dockerfile index dae25be3f..5df13d717 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:bookworm +FROM ruby:3.2-bookworm ENV DEBIAN_FRONTEND=noninteractive diff --git a/Gemfile b/Gemfile index 2765b1ae7..660ff7f1a 100644 --- a/Gemfile +++ b/Gemfile @@ -55,7 +55,6 @@ gem "bootstrap_form", "~> 5.0" gem "cancancan" gem "config" gem "delayed_job_active_record" -gem "dry-schema", "< 1.14.0" # see https://github.com/openstreetmap/openstreetmap-website/issues/5482 gem "dry-validation" gem "frozen_record" gem "http_accept_language", "~> 2.1.1" @@ -139,9 +138,6 @@ gem "image_processing" # Used to validate widths gem "unicode-display_width" -# Lock some modules to old versions for ruby 3.1 support -gem "zeitwerk", "< 2.7" - # Gems useful for development group :development do gem "better_errors" diff --git a/Gemfile.lock b/Gemfile.lock index c5f6f4b79..66f09585d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -92,17 +92,17 @@ GEM autoprefixer-rails (10.4.19.0) execjs (~> 2) aws-eventstream (1.3.1) - aws-partitions (1.1051.0) - aws-sdk-core (3.218.1) + aws-partitions (1.1054.0) + aws-sdk-core (3.219.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) base64 jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.98.0) + aws-sdk-kms (1.99.0) aws-sdk-core (~> 3, >= 3.216.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.181.0) + aws-sdk-s3 (1.182.0) aws-sdk-core (~> 3, >= 3.216.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -231,13 +231,13 @@ GEM concurrent-ruby (~> 1.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-schema (1.13.4) + dry-schema (1.14.0) concurrent-ruby (~> 1.0) dry-configurable (~> 1.0, >= 1.0.1) - dry-core (~> 1.0, < 2) - dry-initializer (~> 3.0) - dry-logic (>= 1.4, < 2) - dry-types (>= 1.7, < 2) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-logic (~> 1.5) + dry-types (~> 1.8) zeitwerk (~> 2.6) dry-types (1.8.2) bigdecimal (~> 3.0) @@ -246,11 +246,11 @@ GEM dry-inflector (~> 1.0) dry-logic (~> 1.4) zeitwerk (~> 2.6) - dry-validation (1.10.0) + dry-validation (1.11.1) concurrent-ruby (~> 1.0) - dry-core (~> 1.0, < 2) - dry-initializer (~> 3.0) - dry-schema (>= 1.12, < 2) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-schema (~> 1.14) zeitwerk (~> 2.6) erb_lint (0.9.0) activesupport @@ -372,7 +372,7 @@ GEM marcel (1.0.4) matrix (0.4.2) maxminddb (0.1.22) - mini_magick (5.1.2) + mini_magick (5.2.0) benchmark logger mini_mime (1.1.5) @@ -579,7 +579,7 @@ GEM lint_roller (~> 1.1) rubocop (>= 1.72.1, < 2.0) rubocop-ast (>= 1.38.0, < 2.0) - rubocop-rails (2.30.1) + rubocop-rails (2.30.2) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) @@ -632,7 +632,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - stringio (3.1.3) + stringio (3.1.5) strong_migrations (1.8.0) activerecord (>= 5.2) teaspoon (1.4.0) @@ -658,7 +658,7 @@ GEM i18n (>= 0.8.0) simpleidn vendorer (0.2.0) - version_gem (1.1.4) + version_gem (1.1.6) webmock (3.25.0) addressable (>= 2.8.0) crack (>= 0.3.2) @@ -671,7 +671,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.18) + zeitwerk (2.7.2) PLATFORMS ruby @@ -708,7 +708,6 @@ DEPENDENCIES doorkeeper doorkeeper-i18n doorkeeper-openid_connect - dry-schema (< 1.14.0) dry-validation erb_lint factory_bot_rails @@ -782,7 +781,6 @@ DEPENDENCIES validates_email_format_of (>= 1.5.1) vendorer webmock - zeitwerk (< 2.7) BUNDLED WITH 2.5.22 diff --git a/INSTALL.md b/INSTALL.md index 8667fb512..cb54cb543 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -22,7 +22,7 @@ of packages required before you can get the various gems installed. ## Minimum requirements -* Ruby 3.1+ +* Ruby 3.2+ * PostgreSQL 13+ * Bundler (see note below about [developer Ruby setup](#rbenv)) * Javascript Runtime diff --git a/app/abilities/api_ability.rb b/app/abilities/api_ability.rb index edf051fae..ef852b69f 100644 --- a/app/abilities/api_ability.rb +++ b/app/abilities/api_ability.rb @@ -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 @@ -40,7 +40,7 @@ class ApiAbility end if user.moderator? - can [:destroy, :restore], ChangesetComment if scopes.include?("write_changeset_comments") + can [:create, :destroy], :changeset_comment_visibility if scopes.include?("write_changeset_comments") can :destroy, Note if scopes.include?("write_notes") diff --git a/app/controllers/api/changeset_comments/visibilities_controller.rb b/app/controllers/api/changeset_comments/visibilities_controller.rb new file mode 100644 index 000000000..397872c11 --- /dev/null +++ b/app/controllers/api/changeset_comments/visibilities_controller.rb @@ -0,0 +1,60 @@ +module Api + module ChangesetComments + class VisibilitiesController < ApiController + before_action :check_api_writable + before_action :authorize + + authorize_resource :class => :changeset_comment_visibility + + before_action :set_request_formats + + ## + # Sets visible flag on comment to true + def create + # Check the arguments are sane + raise OSM::APIBadUserInput, "No id was given" unless params[:changeset_comment_id] + + # Extract the arguments + changeset_comment_id = params[:changeset_comment_id].to_i + + # Find the changeset + comment = ChangesetComment.find(changeset_comment_id) + + # Unhide the comment + comment.update(:visible => true) + + # Return a copy of the updated changeset + @changeset = comment.changeset + + respond_to do |format| + format.xml + format.json + end + end + + ## + # Sets visible flag on comment to false + def destroy + # Check the arguments are sane + raise OSM::APIBadUserInput, "No id was given" unless params[:changeset_comment_id] + + # Extract the arguments + changeset_comment_id = params[:changeset_comment_id].to_i + + # Find the changeset + comment = ChangesetComment.find(changeset_comment_id) + + # Hide the comment + comment.update(:visible => false) + + # Return a copy of the updated changeset + @changeset = comment.changeset + + respond_to do |format| + format.xml + format.json + end + end + end + end +end diff --git a/app/controllers/api/changeset_comments_controller.rb b/app/controllers/api/changeset_comments_controller.rb index 808ac97ea..2f4a361ba 100644 --- a/app/controllers/api/changeset_comments_controller.rb +++ b/app/controllers/api/changeset_comments_controller.rb @@ -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 @@ -59,56 +59,6 @@ module Api end end - ## - # Sets visible flag on comment to false - def destroy - # Check the arguments are sane - raise OSM::APIBadUserInput, "No id was given" unless params[:id] - - # Extract the arguments - id = params[:id].to_i - - # Find the changeset - comment = ChangesetComment.find(id) - - # Hide the comment - comment.update(:visible => false) - - # Return a copy of the updated changeset - @changeset = comment.changeset - render "api/changesets/show" - - respond_to do |format| - format.xml - format.json - end - end - - ## - # Sets visible flag on comment to true - def restore - # Check the arguments are sane - raise OSM::APIBadUserInput, "No id was given" unless params[:id] - - # Extract the arguments - id = params[:id].to_i - - # Find the changeset - comment = ChangesetComment.find(id) - - # Unhide the comment - comment.update(:visible => true) - - # Return a copy of the updated changeset - @changeset = comment.changeset - render "api/changesets/show" - - respond_to do |format| - format.xml - format.json - end - end - private ## diff --git a/app/controllers/api/changesets/downloads_controller.rb b/app/controllers/api/changesets/downloads_controller.rb new file mode 100644 index 000000000..1abc9e459 --- /dev/null +++ b/app/controllers/api/changesets/downloads_controller.rb @@ -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 diff --git a/app/controllers/api/changesets_controller.rb b/app/controllers/api/changesets_controller.rb index 3df7b75ce..7f0ee1276 100644 --- a/app/controllers/api/changesets_controller.rb +++ b/app/controllers/api/changesets_controller.rb @@ -63,7 +63,7 @@ module Api @changeset = Changeset.find(params[:id]) if params[:include_discussion].presence @comments = @changeset.comments - @comments = @comments.unscope(:where => :visible) if params[:show_hidden_comments].presence && can?(:restore, ChangesetComment) + @comments = @comments.unscope(:where => :visible) if params[:show_hidden_comments].presence && can?(:create, :changeset_comment_visibility) @comments = @comments.includes(:author) end @@ -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. diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index 5d817c9c6..fbeb01b76 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -43,7 +43,7 @@ class NotesController < ApplicationController @note_includes_anonymous = @note.author.nil? || @note_comments.find { |comment| comment.author.nil? } - @note_comments = @note_comments.drop(1) if @note.author.nil? || @note.author.active? + @note_comments = @note_comments.drop(1) if @note_comments.first&.event == "opened" rescue ActiveRecord::RecordNotFound render :template => "browse/not_found", :status => :not_found end diff --git a/app/controllers/users/lists_controller.rb b/app/controllers/users/lists_controller.rb index a2f35e9b2..7e3fa2a32 100644 --- a/app/controllers/users/lists_controller.rb +++ b/app/controllers/users/lists_controller.rb @@ -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 diff --git a/app/helpers/note_helper.rb b/app/helpers/note_helper.rb index 0ba503228..7a75a4ff5 100644 --- a/app/helpers/note_helper.rb +++ b/app/helpers/note_helper.rb @@ -1,9 +1,11 @@ module NoteHelper include ActionView::Helpers::TranslationHelper - def note_description(author, description) + def note_description(author, description, first_comment) if !author.nil? && author.status == "deleted" RichText.new("text", t("notes.show.description_when_author_is_deleted")) + elsif first_comment&.event != "opened" + RichText.new("text", t("notes.show.description_when_there_is_no_opening_comment")) else description end diff --git a/app/helpers/svg_helper.rb b/app/helpers/svg_helper.rb index b04ab1b0d..7fb6b4321 100644 --- a/app/helpers/svg_helper.rb +++ b/app/helpers/svg_helper.rb @@ -5,12 +5,12 @@ module SvgHelper tag.svg path_tag, :width => 16, :height => 16 end - def previous_page_svg_tag(**options) - adjacent_page_svg_tag(dir == "rtl" ? 1 : -1, **options) + def previous_page_svg_tag(**) + adjacent_page_svg_tag(dir == "rtl" ? 1 : -1, **) end - def next_page_svg_tag(**options) - adjacent_page_svg_tag(dir == "rtl" ? -1 : 1, **options) + def next_page_svg_tag(**) + adjacent_page_svg_tag(dir == "rtl" ? -1 : 1, **) end def key_svg_tag(**options) diff --git a/app/models/note.rb b/app/models/note.rb index b7215d6f7..0a1f4abd7 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -95,7 +95,7 @@ class Note < ApplicationRecord # Return the note's description, derived from the first comment def description if user_ip.nil? && user_id.nil? - all_comments.first.body + all_comments.first.body if all_comments.first&.event == "opened" else RichText.new("text", super) end @@ -104,7 +104,7 @@ class Note < ApplicationRecord # Return the note's author object, derived from the first comment def author if user_ip.nil? && user_id.nil? - all_comments.first.author + all_comments.first.author if all_comments.first&.event == "opened" else super end diff --git a/app/views/api/changeset_comments/visibilities/create.json.jbuilder b/app/views/api/changeset_comments/visibilities/create.json.jbuilder new file mode 100644 index 000000000..c245cd15c --- /dev/null +++ b/app/views/api/changeset_comments/visibilities/create.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "api/root_attributes" + +json.changeset do + json.partial! "api/changesets/changeset", :changeset => @changeset +end diff --git a/app/views/api/changeset_comments/visibilities/create.xml.builder b/app/views/api/changeset_comments/visibilities/create.xml.builder new file mode 100644 index 000000000..84892f767 --- /dev/null +++ b/app/views/api/changeset_comments/visibilities/create.xml.builder @@ -0,0 +1,5 @@ +xml.instruct! :xml, :version => "1.0" + +xml.osm(OSM::API.new.xml_root_attributes) do |osm| + osm << render(:partial => "api/changesets/changeset", :object => @changeset) +end diff --git a/app/views/api/changeset_comments/visibilities/destroy.json.jbuilder b/app/views/api/changeset_comments/visibilities/destroy.json.jbuilder new file mode 100644 index 000000000..c245cd15c --- /dev/null +++ b/app/views/api/changeset_comments/visibilities/destroy.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "api/root_attributes" + +json.changeset do + json.partial! "api/changesets/changeset", :changeset => @changeset +end diff --git a/app/views/api/changeset_comments/visibilities/destroy.xml.builder b/app/views/api/changeset_comments/visibilities/destroy.xml.builder new file mode 100644 index 000000000..84892f767 --- /dev/null +++ b/app/views/api/changeset_comments/visibilities/destroy.xml.builder @@ -0,0 +1,5 @@ +xml.instruct! :xml, :version => "1.0" + +xml.osm(OSM::API.new.xml_root_attributes) do |osm| + osm << render(:partial => "api/changesets/changeset", :object => @changeset) +end diff --git a/app/views/api/changesets/download.xml.builder b/app/views/api/changesets/downloads/show.xml.builder similarity index 55% rename from app/views/api/changesets/download.xml.builder rename to app/views/api/changesets/downloads/show.xml.builder index 1e400cd9f..88e05b587 100644 --- a/app/views/api/changesets/download.xml.builder +++ b/app/views/api/changesets/downloads/show.xml.builder @@ -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 diff --git a/app/views/changesets/index.atom.builder b/app/views/changesets/index.atom.builder index c8ffe1a81..6556f12bf 100644 --- a/app/views/changesets/index.atom.builder +++ b/app/views/changesets/index.atom.builder @@ -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") diff --git a/app/views/changesets/show.html.erb b/app/views/changesets/show.html.erb index 167bcb5cb..70b1877b5 100644 --- a/app/views/changesets/show.html.erb +++ b/app/views/changesets/show.html.erb @@ -49,8 +49,8 @@ — <%= tag.button t(".#{comment.visible ? 'hide' : 'unhide'}_comment"), :class => "btn btn-sm small btn-link link-secondary p-0 align-baseline", - :data => { :method => "POST", - :url => comment.visible ? changeset_comment_hide_url(comment) : changeset_comment_unhide_url(comment) } %> + :data => { :method => comment.visible ? "DELETE" : "POST", + :url => api_changeset_comment_visibility_path(comment) } %> <% end %>
@@ -81,7 +81,7 @@ :name => "comment", :disabled => true, :data => { :method => "POST", - :url => changeset_comment_url(@changeset) } %> + :url => api_changeset_changeset_comments_path(@changeset) } %>
<% else %> @@ -105,9 +105,9 @@
- <%= link_to(t(".changesetxml"), :controller => "api/changesets", :action => "show") %> + <%= link_to t(".changesetxml"), api_changeset_path(@changeset) %> · - <%= link_to(t(".osmchangexml"), :controller => "api/changesets", :action => "download") %> + <%= link_to t(".osmchangexml"), api_changeset_download_path(@changeset) %>
<% if @next_by_user || @prev_by_user %> diff --git a/app/views/notes/index.html.erb b/app/views/notes/index.html.erb index 0b39234a9..4bd7d499d 100644 --- a/app/views/notes/index.html.erb +++ b/app/views/notes/index.html.erb @@ -48,7 +48,7 @@ <%= link_to note.id, note %> <%= note_author(note.author) %> - <%= note_description(note.author, note.description).to_html %> + <%= note_description(note.author, note.description, current_user&.moderator? ? note.comments.unscope(:where => :visible).first : note.comments.first).to_html %> <%= friendly_date_ago(note.created_at) %> <%= friendly_date_ago(note.updated_at) %> diff --git a/app/views/notes/show.html.erb b/app/views/notes/show.html.erb index b65926b5f..d0dcdeb1b 100644 --- a/app/views/notes/show.html.erb +++ b/app/views/notes/show.html.erb @@ -5,7 +5,7 @@

<%= t(".description") %>

- <%= note_description(@note.author, @note.description).to_html %> + <%= note_description(@note.author, @note.description, current_user&.moderator? ? @note.comments.unscope(:where => :visible).first : @note.comments.first).to_html %>
diff --git a/app/views/users/lists/show.html.erb b/app/views/users/lists/show.html.erb index dd037c7af..c3d15d18a 100644 --- a/app/views/users/lists/show.html.erb +++ b/app/views/users/lists/show.html.erb @@ -17,6 +17,13 @@ :data => { :behavior => "category_dropdown" }, :class => "form-select" %>
+
+ <%= text_field_tag :username, + params[:username], + :placeholder => t(".name_or_email"), + :autocomplete => "on", + :class => "form-control" %> +
<%= text_field_tag :ip, params[:ip], diff --git a/bin/setup b/bin/setup index ff6a47532..ced1ba370 100755 --- a/bin/setup +++ b/bin/setup @@ -4,8 +4,8 @@ require "fileutils" APP_ROOT = File.expand_path("..", __dir__) APP_NAME = "openstreetmap".freeze -def system!(*args) - system(*args, :exception => true) +def system!(*) + system(*, :exception => true) end FileUtils.chdir APP_ROOT do diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb index e7b813b73..710e2c009 100644 --- a/config/initializers/cors.rb +++ b/config/initializers/cors.rb @@ -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 diff --git a/config/locales/be.yml b/config/locales/be.yml index c2631f5f0..c32740cbc 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -292,6 +292,7 @@ be: accounts: show: title: Рэдагаваць уліковы запіс + my_account: Мой уліковы запіс current email address: Бягучы адрас электроннай пошты external auth: Знешняя Аўтэнтыфікацыя openid: @@ -373,6 +374,7 @@ be: Калі ласка, прайдзіце па спасылцы і азнаёмцеся з тэкстам.' read_tou: Я згаджаюся з Умовамі выкарыстання continue: Працягнуць + cancel: Скасаваць you need to accept or decline: Калі ласка, прачытайце, а потым згадзіцеся ці адхіліце новыя ўмовы супрацоўніцтва для працягу. legale_select: 'Краіна пражывання:' diff --git a/config/locales/cs.yml b/config/locales/cs.yml index d56e45588..6d556b020 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -138,6 +138,7 @@ cs: allow_write_prefs: měnit jejich uživatelské nastavení allow_write_diary: vytvářet deníkové záznamy a komentáře allow_write_api: upravovat mapu + allow_write_changeset_comments: komentovat sady změn allow_read_gpx: číst jejich soukromé GPS stopy allow_write_gpx: nahrávat GPS stopy allow_write_notes: měnit poznámky @@ -319,6 +320,7 @@ cs: accounts: show: title: Upravit účet + my_account: Můj účet current email address: Stávající e-mailová adresa external auth: Externí autentizace openid: @@ -333,6 +335,9 @@ cs: agreed_with_pd: Také jste prohlásili, že své editace považujete za volné dílo. link: https://wiki.openstreetmap.org/wiki/Cs:Open_Database_License/Contributor_Terms?uselang=cs link text: co to znamená? + not_agreed_with_pd: Neprohlásili jste, že své editace považujete za volné + dílo. + pd_link_text: prohlásit save changes button: Uložit změny delete_account: Smazat účet… go_public: @@ -414,6 +419,18 @@ cs: pro přispěvatele. Podrobnější informace najdete na %{terms_declined_link}. terms_declined_link: této wikistránce terms_declined_url: http://wiki.openstreetmap.org/wiki/CS:Contributor_Terms_Declined?uselang=cs + pd_declarations: + show: + title: Považujte mé příspěvky za volné dílo + consider_pd: Považuji své příspěvky za volné dílo + consider_pd_why: Proč bych mohl chtít, aby moje příspěvky byly volným dílem? + confirm: Potvrdit + create: + successfully_declared: Úspěšně jste prohlásili, že své příspěvky považujete + za volné dílo. + already_declared: Již dříve jste prohlásili, že své příspěvky považujete za + volné dílo. + did_not_confirm: Nepotvrdili jste, že považujete své příspěvky za volné dílo. browse: deleted_ago_by_html: Smazáno %{time_ago} uživatelem %{user} edited_ago_by_html: Upraveno %{time_ago} uživatelem %{user} @@ -489,6 +506,7 @@ cs: start_rjs: feature_warning: Načítá se %{num_features} prvků, což může váš prohlížeč zpomalit či zablokovat. Určitě chcete tato data zobrazit? + feature_error: 'Nepodařilo se načíst prvky: %{message}' load_data: Nahrát data loading: Načítá se… tag_details: @@ -1055,6 +1073,7 @@ cs: bridleway: Koňská stezka bus_guideway: Autobusová dráha bus_stop: Autobusová zastávka + busway: Trasa metrobusu construction: Silnice ve výstavbě corridor: Koridor crossing: Přechod @@ -1745,6 +1764,9 @@ cs: offline_flash: osm_offline: Databáze OpenStreetMap je momentálně kvůli probíhající neodkladné údržbě mimo provoz. + osm_read_only: Databáze OpenStreetMap je momentálně kvůli probíhající neodkladné + údržbě pouze pro čtení. + expected_restore_html: Očekáváme se, že služby budou obnoveny v %{time}. announcement: Oznámení si můžete přečíst zde. user_mailer: diary_comment_notification: @@ -2813,10 +2835,12 @@ cs: write_prefs: Měnit preference uživatele write_diary: Vytvářet deníkové záznamy a komentáře write_api: Upravovat mapu + write_changeset_comments: Komentovat sady změn read_gpx: Číst soukromé GPS stopy write_gpx: Nahrávat GPS stopy write_notes: Měnit poznámky write_redactions: Skrývat mapová data + write_blocks: Vytvářet a ruÅ¡it blokování uživatelů read_email: Přečíst e-mailovou adresu uživatele consume_messages: Číst, aktualizovat stav a mazat zprávy uživatelů send_messages: Posílat soukromé zprávy jiným uživatelům @@ -2925,6 +2949,7 @@ cs: my notes: Moje poznámky k mapě my messages: Moje zprávy my profile: Můj profil + my_account: Můj účet my comments: Moje komentáře my_preferences: Moje preference my_dashboard: Moje nástěnka @@ -3006,6 +3031,16 @@ cs: show: title: Uživatelé heading: Uživatelé + select_status: Vyberte stav + states: + pending: Čekající + active: Aktivní + confirmed: Potvrzený + suspended: Pozastavený + deleted: Smazaný + name_or_email: Jméno nebo e-mail + ip_address: IP adresa + search: Hledat page: found_users: one: Nalezen %{count} uživatel @@ -3220,6 +3255,7 @@ cs: closed_title: 'VyřeÅ¡ená poznámka #%{note_name}' hidden_title: 'Skrytá poznámka #%{note_name}' description_when_author_is_deleted: smazáno + description_when_there_is_no_opening_comment: neznámé event_opened_by_html: Vytvořeno uživatelem %{user} %{time_ago} event_opened_by_anonymous_html: Vytvořeno anonymním uživatelem %{time_ago} event_commented_by_html: Komentář od uživatele %{user} %{time_ago} @@ -3458,6 +3494,8 @@ cs: ninth: "9." tenth: "10." time: Čas + download: Stáhnout trasu jako GeoJSON + filename: trasa query: node: Uzel way: Cesta @@ -3472,6 +3510,9 @@ cs: show_address: Zobrazit adresu query_features: Průzkum prvků centre_map: Zde vystředit mapu + home: + marker_title: Poloha mého domova + not_set: Ve vaÅ¡em účtu není nastavena poloha domova redactions: edit: heading: Upravit redakci diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 3fbdb3b19..c26712ca1 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -90,6 +90,7 @@ cy: allow_write_prefs: addasu eu dewisiadau defnyddiwr allow_write_diary: creu cofnodion dyddiadur a sylwadau allow_write_api: golygu'r map + allow_write_changeset_comments: rhoi sylwadau ar grwpiau newid allow_read_gpx: darllen eu harllwybrau GPS allow_write_gpx: uwchlwytho olion GPS allow_write_notes: addasu nodiadau @@ -292,9 +293,11 @@ cy: accounts: show: title: Golygu cyfrif + my_account: Fy Nghyfrif current email address: Cyfeiriad E-bost Cyfredol external auth: Dilysu Allanol openid: + link: https://wiki.openstreetmap.org/wiki/OpenID link text: beth yw hwn? contributor terms: heading: Telerau Cyfranwyr @@ -304,7 +307,11 @@ cy: newydd. agreed_with_pd: Rydych hefyd wedi datgan eich bod yn ystyried bod eich golygiadau yn y Parth Cyhoeddus. + link: https://osmfoundation.org/wiki/Licence/Contributor_Terms link text: beth yw hwn? + not_agreed_with_pd: Nid ydych wedi datgan eich bod yn ystyried bod eich golygiadau + yn y Parth Cyhoeddus. + pd_link_text: datgan save changes button: Cadw Newidiadau delete_account: Dileu Cyfrif... go_public: @@ -338,6 +345,8 @@ cy: a lleoliad cartref yn cael eu dileu. delete_display_name: Bydd eich enw defnyddiwr yn cael ei ddileu, a gellir ei ailddefnyddio gan gyfrifon eraill. + retain_caveats: 'Fodd bynnag, bydd rhywfaint o wybodaeth amdanoch yn cael + ei chadw ar OpenStreetMap, hyd yn oed ar ôl i''ch cyfrif gael ei ddileu:' retain_edits: Bydd eich golygiadau i'r gronfa ddata mapiau, os ydynt yn bodoli, yn cael eu cadw. retain_traces: Cedwir unrhyw olion rydych chi wedi uwchlwytho os ydynt yn @@ -374,7 +383,14 @@ cy: terms_declined_url: https://wiki.openstreetmap.org/wiki/Contributor_Terms_Declined pd_declarations: show: + title: Ystyried bod fy nghyfraniadau yn y Parth Cyhoeddus + consider_pd: Ystyriaf fod fy nghyfraniadau yn y Parth Cyhoeddus + consider_pd_why: Pam fyddwn am gael fy nghyfraniadau yn y Parth Cyhoeddus? consider_pd_why_url: https://osmfoundation.org/wiki/Licence_and_Legal_FAQ/Why_would_I_want_my_contributions_to_be_public_domain + confirm: Cadarnhau + create: + successfully_declared: Rydych wedi datgan yn llwyddiannus eich bod yn ystyried + bod eich golygiadau yn y Parth Cyhoeddus. browse: deleted_ago_by_html: Dilëwyd %{time_ago} gan %{user} edited_ago_by_html: Golygwyd %{time_ago} gan %{user} @@ -444,7 +460,7 @@ cy: title: Heb ei Ganfod timeout: title: Gwall Goramser - sorry: Sori, cymerodd yn rhy hir i adalw data math %{type} gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl data %{type} #%{id}.' type: node: nod way: llwybr @@ -462,6 +478,7 @@ cy: start_rjs: feature_warning: Wrthi'n llwytho %{num_features} nodwedd, a all arafu neu chwalu eich porwr. Ydych chi wir eisiau gweld y data? + feature_error: 'Ni ellid llwytho nodweddion: %{message}' load_data: Llwytho Data loading: Wrthi'n llwytho... tag_details: @@ -492,29 +509,37 @@ cy: view_redacted_data: Gweld Data Wedi'i Gorchuddio view_redaction_message: Gweld Neges Orchuddio nodes: + not_found_message: + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i nod #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw data'r nod gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl data nod #%{id}.' old_nodes: not_found_message: - sorry: 'Sori, ni ellir canfod fersiwn %{version} o''r nod #%{id}.' + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i fersiwn %{version} o nod #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw hanes y nod gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl hanes nod #%{id}.' ways: + not_found_message: + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i lwybr #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw data'r llwybr gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl data llwybr #%{id}.' old_ways: not_found_message: - sorry: 'Sori, ni ellir canfod fersiwn %{version} o lwybr #%{id}.' + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i fersiwn %{version} o lwybr + #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw hanes y llwybr gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl hanes llwybr #%{id}.' relations: + not_found_message: + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i berthynas #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw data'r perthynas gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl data perthynas #%{id}.' old_relations: not_found_message: - sorry: 'Sori, ni ellir canfod fersiwn %{version} o''r perthynas #%{id}.' + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i fersiwn %{version} o berthynas + #%{id}.' timeout: - sorry: Sori, cymerodd yn rhy hir i adalw hanes y perthynas gyda'r id %{id}. + sorry: 'Mae''n ddrwg gennym, cymerodd rhy hir i nôl hanes perthynas #%{id}.' changeset_comments: feeds: comment: @@ -524,8 +549,8 @@ cy: title_all: Trafodaeth grŵp newid OpenStreetMap title_particular: Trafodaeth grŵp newid OpenStreetMap %{changeset_id} timeout: - sorry: Sori, cymerodd yn rhy hir i adalw rhestr o sylwadau grŵp newid y gofynnoch - amdanynt. + sorry: Mae'n ddrwg gennym, cymerodd rhy hir i nôl rhestr o sylwadau grŵp newid + y gofynnoch amdanynt. changesets: changeset: no_edits: (dim golygiadau) @@ -534,6 +559,7 @@ cy: title: Grwpiau newid title_user: Grwpiau newid gan %{user} title_user_link_html: Grwpiau newid gan %{user_link} + title_followed: Grwpiau newid gan bobl rydych yn eu dilyn title_nearby: Grwpiau newid gan ddefnyddwyr gerllaw empty: Heb ganfod grwpiau newid. empty_area: Heb ganfod grwpiau newid yn yr ardal hon. @@ -576,9 +602,11 @@ cy: ways_paginated: Llwybrau (%{x}-%{y} o %{count}) relations: Perthnasau (%{count}) relations_paginated: Perthnasau (%{x}-%{y} o %{count}) + not_found_message: + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i grŵp newid #%{id}.' timeout: - sorry: Sori, cymerodd y rhestr o grwpiau newid y gofynnoch amdanynt rhy hir - i'w hadalw. + sorry: Mae'n ddrwg gennym, cymerodd rhy hir i nôl rhestr o grŵp newid y gofynnoch + amdanynt. changeset_subscriptions: show: subscribe: @@ -592,8 +620,8 @@ cy: created_by_html: Crëwyd gan %{link_user} ar %{created}. no_such_entry: heading: 'Dim cofnod gyda''r id: %{id}' - body: Mae'n ddrwg gennym, nid oes grŵp newid gyda'r id %{id}. Gwiriwch eich - sillafu, neu efallai bod y ddolen rydych chi wedi ei chlicio arni'n anghywir. + body: Mae'n ddrwg gennym, nid oes grŵp newid gyda'r cyfeirnod %{id}. Gwiriwch + eich sillafu, neu efallai bod y ddolen rydych chi wedi ei chlicio arni'n anghywir. dashboards: contact: km away: '%{count}km i ffwrdd' @@ -649,9 +677,9 @@ cy: no_such_entry: title: Dim cofnod dyddiadur heading: 'Dim cofnod gyda''r id: %{id}' - body: Mae'n ddrwg gennym, nid oes cofnod dyddiadur neu sylw gyda'r id %{id}. - Gwiriwch eich sillafu, neu efallai bod y ddolen rydych chi wedi ei chlicio - arni'n anghywir. + body: Mae'n ddrwg gennym, nid oes cofnod dyddiadur neu sylw gyda'r cyfeirnod + %{id}. Gwiriwch eich sillafu, neu efallai bod y ddolen rydych chi wedi ei + chlicio arni'n anghywir. diary_entry: posted_by_html: Postiwyd gan %{link_user} ar %{created} yn %{language_link} updated_at_html: Diweddarwyd ddiwethaf ar %{updated}. @@ -745,10 +773,15 @@ cy: heading: Ydych chi am ddilyn %{user}? button: Dilyn Defnyddiwr unfollow: + heading: Ydych chi am ddad-ddilyn %{user}? button: Dad-ddilyn Defnyddiwr create: success: Rydych nawr yn dilyn %{name}! + failed: Mae'n ddrwg gennym, mae eich cais i ddilyn %{name} wedi methu. already_followed: Rydych chi eisoes yn dilyn %{name}. + destroy: + success: Rydych chi wedi dad-ddilyn %{name}. + not_followed: Nid ydych yn dilyn %{name}. geocoder: search: title: @@ -1001,6 +1034,7 @@ cy: bridleway: Llwybr Ceffyl bus_guideway: Lon Bysiau bus_stop: Safle Bws + busway: Ffordd Fws construction: Priffordd yn cael ei Adeiladu corridor: Coridor crossing: Croesfan @@ -1163,6 +1197,8 @@ cy: track: Trac Rhedeg water_park: Parc Dŵr "yes": Hamdden + lock: + "yes": Loc man_made: adit: Adit advertising: Hysbysebu @@ -1509,6 +1545,9 @@ cy: reservoir: Cronfa Ddŵr basin: Basn Dwr fishpond: Pwll Pysgod + lagoon: Lagŵn + wastewater: Dŵr Gwastraff + lock: Loc waterway: artificial: Dyfrffyrdd Artiffisial boatyard: Iard Gychod @@ -1564,6 +1603,7 @@ cy: reports: Adroddiadau last_updated: Diweddarwyd ddiwethaf last_updated_time_ago_user_html: '%{time_ago} gan %{user}' + reporting_users: Defnyddiwyr sydd wedi rhoi gwybod reports_count: zero: '%{count} Adroddiad' one: '%{count} Adroddiad' @@ -1571,6 +1611,7 @@ cy: few: '%{count} Adroddiad' many: '%{count} Adroddiad' other: '%{count} Adroddiad' + more_reporters: a %{count} arall reported_item: Eitem a roddwyd gwybod states: ignored: Anwybyddwyd @@ -1609,6 +1650,8 @@ cy: reopened: Mae statws y mater wedi'i osod i 'Agored' comments: comment_from_html: Sylw gan %{user_link} ar %{comment_created_at} + reassign_to_moderators: Ailbennu Mater i Gymedrolwyr + reassign_to_administrators: Ailbennu Mater i Weinyddwyr reports: reported_by_html: Adroddwyd fel %{category} gan %{user} ar %{updated_at} helper: @@ -1686,6 +1729,13 @@ cy: communities: Cymunedau learn_more: Dysgu Rhagor more: Rhagor + offline_flash: + osm_offline: Mae cronfa ddata OpenStreetMap all-lein ar hyn o bryd er mwyn gwneud + gwaith cynnal a chadw hanfodol. + osm_read_only: Nid yw'n bosib golygu cronfa ddata OpenStreetMap ar hyn o bryd + tra bod gwaith cynnal a chadw hanfodol yn digwydd. + expected_restore_html: Disgwylir i wasanaethau gael eu hadfer ymhen %{time}. + announcement: Gallwch ddarllen y cyhoeddiad yma. user_mailer: diary_comment_notification: description: 'Cofnod Dyddiadur OpenStreetMap #%{id}' @@ -1707,8 +1757,11 @@ cy: follow_notification: hi: Helo %{to_user}, subject: '[OpenStreetMap] Mae %{user} wedi eich dilyn' + followed_you: Mae %{user} bellach yn eich dilyn ar OpenStreetMap. see_their_profile: 'Gallwch weld eu proffil yma: %{userurl}.' see_their_profile_html: 'Gallwch weld eu proffil yma: %{userurl}.' + follow_them: Gallwch hefyd ddilyn y defnyddiwr hwn yn %{followurl}. + follow_them_html: Gallwch hefyd ddilyn y defnyddiwr hwn yn %{followurl}. gpx_details: details: 'Manylion eich ffeil:' filename: Enw ffeil @@ -1832,7 +1885,7 @@ cy: no_such_message: title: Dim neges o'r fath heading: Dim neges o'r fath - body: Sori, nid oes neges gyda'r id yno. + body: Mae'n ddrwg gennym, nid oes neges gyda'r cyfeirnod yno. show: title: Darllen neges reply_button: Ateb @@ -1977,7 +2030,7 @@ cy: login_button: Mewngofnodi with external: neu fewngofnodi gyda thrydydd parti or: neu - auth failure: Mae'n ddrwg gennym, ni ellir mewngofnodi gyda'r manylion hynny. + auth failure: Mae'n ddrwg gennym, ni ellid mewngofnodi gyda'r manylion hynny. destroy: title: Allgofnodi heading: Allgofnodi o OpenStreetMap @@ -2237,6 +2290,8 @@ cy: not_public_flash: not_public: Nid ydych wedi gosod eich golygiadau i fod yn gyhoeddus. user_page_link: tudalen defnyddiwr + anon_edits_html: (%{link}) + anon_edits_link: https://wiki.openstreetmap.org/wiki/Disabling_anonymous_edits anon_edits_link_text: Gweld pam. edit: id_not_configured: iD heb ei ffurfweddu @@ -2504,8 +2559,8 @@ cy: trace_uploaded: Mae eich ffeil GPX wedi'i huwchlwytho ac yn aros i gael ei chynnwys yn y gronfa ddata. Bydd hyn fel arfer yn digwydd o fewn hanner awr, a bydd e-bost yn cael ei anfon atoch ar ôl cwblhau. - upload_failed: Mae'n ddrwg gennym, methodd eich uwchlwythiad GPX. Mae gweinyddwr - wedi cael gwybod am y gwall. Ceisiwch eto. + upload_failed: Mae'n ddrwg gennym, mae eich uwchlwythiad GPX wedi methu. Mae + gweinyddwr wedi cael gwybod am y gwall. Ceisiwch eto. traces_waiting: zero: Mae gennych %{count} ôl yn aros i'w uwchlwytho. Arhoswch i'r rhain orffen cyn uwchlwytho rhagor, er mwyn osgoi rhwystro'r ciw i ddefnyddwyr eraill. @@ -2669,10 +2724,12 @@ cy: write_prefs: Addasu dewisiadau defnyddwyr write_diary: Creu cofnodion dyddiadur a sylwadau write_api: Golygu'r map + write_changeset_comments: Rhoi sylwadau ar grwpiau newid read_gpx: Darllen olion GPS preifat write_gpx: Uwchlwytho olion GPS write_notes: Addasu nodiadau write_redactions: Gorchuddio data map + write_blocks: Creu a dirymu blociau defnyddwyr read_email: Darllen cyfeiriad e-bost defnyddwyr consume_messages: Darllen, diweddaru statws a dileu negeseuon defnyddiwr send_messages: Anfon negeseuon preifat at ddefnyddwyr eraill @@ -2697,6 +2754,8 @@ cy: confirm_delete: Dileu'r ap hwn? client_id: ID Cleient client_secret: Cyfrinach Cleient + client_secret_warning: Gwnewch yn siŵr eich bod yn cadw'r gyfrinach hon - ni + fydd ar gael i chi eto permissions: Caniatadau redirect_uris: Ailgyfeirio URIs oauth2_authorizations: @@ -2752,6 +2811,7 @@ cy: my notes: Nodiadau my messages: Negeseuon my profile: Proffil + my_account: Fy Nghyfrif my comments: Sylwadau my_preferences: Dewisiadau my_dashboard: Dangosfwrdd @@ -2836,6 +2896,16 @@ cy: show: title: Defnyddwyr heading: Defnyddwyr + select_status: Dewiswch Statws + states: + pending: Arfaethedig + active: Gweithredol + confirmed: Cadarnhawyd + suspended: Wedi'u hatal + deleted: Wedi'u dileu + name_or_email: Enw neu Gyfeiriad E-bost + ip_address: Cyfeiriad IP + search: Chwilio page: found_users: zero: Canfuwyd %{count} defnyddiwr @@ -2852,8 +2922,9 @@ cy: summary_no_ip_html: '%{name} wedi''i greu ar %{date}' comments: index: + heading_html: Sylwadau %{user} changesets: Grwpiau newid - diary_entries: Cofnodion dyddiadur + diary_entries: Cofnodion Dyddiadur no_comments: Dim sylwadau changeset_comments: index: @@ -2872,9 +2943,11 @@ cy: suspended: title: Cyfrif wedi'i atal heading: Cyfrif wedi'i atal - support: cymorth + support: chymorth automatically_suspended: Mae'n ddrwg gennym, mae eich cyfrif wedi'i atal yn awtomatig oherwydd gweithgarwch amheus. + contact_support_html: Bydd y penderfyniad hwn yn cael ei adolygu gan weinyddwr + yn fuan, neu gallwch gysylltu â %{support_link} os hoffech drafod hyn. auth_failure: no_authorization_code: Dim cod awdurdodi invalid_scope: Sgop annilys @@ -3034,6 +3107,8 @@ cy: open_title: 'Nodyn heb ei ddatrys #%{note_name}' closed_title: 'Nodyn wedi''i ddatrys #%{note_name}' hidden_title: 'Nodyn cudd #%{note_name}' + description_when_author_is_deleted: wedi'i ddileu + description_when_there_is_no_opening_comment: anhysbys event_opened_by_html: Crëwyd gan %{user} %{time_ago} event_opened_by_anonymous_html: Crëwyd gan berson ddienw %{time_ago} event_commented_by_html: Sylw gan %{user} %{time_ago} @@ -3067,11 +3142,25 @@ cy: wybod i fapwyr eraill fel y gallwn ei ddatrys. Symudwch y marciwr i'r safle cywir ac ysgrifennwch nodyn i esbonio'r broblem. anonymous_warning_html: Nid ydych chi wedi mewngofnodi. %{log_in} neu %{sign_up} - os ydych chi eisiau derbyn diweddariadau am eich nodyn. + os ydych am gael diweddariadau ar gyfer eich nodyn a helpu mapwyr eraill i'w + ddatrys. anonymous_warning_log_in: Mewngofnodwch anonymous_warning_sign_up: gofrestrwch + counter_warning_html: Rydych chi eisoes wedi creu o leiaf %{x_anonymous_notes}, + sy'n wych i'r gymuned, diolch! Nawr rydym yn eich annog i %{contribute_by_yourself}, + nid yw mor gymhleth â hynny, a %{community_can_help}. + x_anonymous_notes: + zero: '%{count} nodyn dienw' + one: '%{count} nodyn dienw' + two: '%{count} nodyn dienw' + few: '%{count} nodyn dienw' + many: '%{count} nodyn dienw' + other: '%{count} nodyn dienw' counter_warning_guide_link: + text: gyfrannu eich hun url: https://wiki.openstreetmap.org/wiki/Beginners%27_guide + counter_warning_forum_link: + text: gall y gymuned eich helpu advice: Mae eich nodyn yn gyhoeddus a gellid ei ddefnyddio i ddiweddaru'r map, felly peidiwch ag ysgrifennu gwybodaeth bersonol, na gwybodaeth o fapiau hawlfreintiedig neu gyfeiriaduron. @@ -3084,6 +3173,8 @@ cy: showing_page: Tudalen %{page} next: Nesaf previous: Cynt + not_found_message: + sorry: 'Mae''n ddrwg gennym, ni ellid dod o hyd i nodyn #%{id}.' javascripts: close: Cau share: @@ -3187,7 +3278,7 @@ cy: distance_km: '%{distance}km' errors: no_route: Ni ellir dod o hyd i'r llwybr rhwng y ddau le. - no_place: Ymddiheuriadau - ni ellir canfod '%{place}'. + no_place: Mae'n ddrwg gennym - ni ellid dod o hyd i '%{place}'. instructions: continue_without_exit: Parhau ar %{name} slight_right_without_exit: Ychydig i'r dde i %{name} @@ -3263,6 +3354,8 @@ cy: ninth: 9fed tenth: 10fed time: Amser + download: Lawrlwytho'r llwybr fel GeoJSON + filename: ffordd query: node: Nod way: Llwybr @@ -3277,6 +3370,9 @@ cy: show_address: Dangos cyfeiriad query_features: Ymholiad nodweddion centre_map: Canoli'r map yma + home: + marker_title: Fy lleoliad cartref + not_set: Nid yw lleoliad cartref wedi'i osod ar gyfer eich cyfrif redactions: edit: heading: Golygu Gorchuddiad diff --git a/config/locales/da.yml b/config/locales/da.yml index 5a1df55c9..ec46ad5e6 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -291,7 +291,7 @@ da: fælleseje/uden ophavsret. link text: hvad er dette? not_agreed_with_pd: Du har ikke erklæret, at du anser dine ændringer for at - være i det offentlige domæne, dvs. fælleseje/uden ophavsret. + være i det offentlige domæne (Public Domain), dvs. fælleseje/uden ophavsret. pd_link_text: erklær save changes button: Gem ændringer delete_account: Slet konto @@ -380,8 +380,8 @@ da: show: title: Betragt mine bidrag for at være i det offentlige domæne consider_pd: Jeg anser mine bidrag for at være i det offentlige domæne - consider_pd_why: Hvorfor skulle jeg gerne have, at mine bidrag er i det offentlige - domæne? + consider_pd_why: Hvorfor skulle jeg have et ønske om, at mine bidrag er i + det offentlige domæne? confirm: Bekræft create: successfully_declared: Du har erklæret, at du anser dine redigeringer for @@ -2978,6 +2978,7 @@ da: confirmed: Bekræftet suspended: Suspenderet deleted: Slettet + name_or_email: Navn eller e-mail ip_address: IP-adresse search: Søg page: @@ -3189,6 +3190,7 @@ da: closed_title: 'Løst bemærkning #%{note_name}' hidden_title: 'Skjult bemærkning #%{note_name}' description_when_author_is_deleted: slettet + description_when_there_is_no_opening_comment: ukendt event_opened_by_html: Oprettet af %{user} %{time_ago} event_opened_by_anonymous_html: Oprettet af anonym %{time_ago} event_commented_by_html: Kommentar fra %{user} %{time_ago} @@ -3423,6 +3425,8 @@ da: ninth: "9." tenth: "10." time: Tid + download: Download rute som GeoJSON + filename: rute query: node: Punkt way: Vej diff --git a/config/locales/de.yml b/config/locales/de.yml index 88021a200..0a1be26ba 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -72,6 +72,7 @@ # Author: Manfredbrandl # Author: Markobr # Author: MarkusHD +# Author: Marwin H.H. # Author: McDutchie # Author: Mcandri13 # Author: Mcliquid @@ -3138,6 +3139,7 @@ de: confirmed: Bestätigt suspended: Ausgesetzt deleted: Gelöscht + name_or_email: Name oder E-Mail ip_address: IP-Adresse search: Suchen page: @@ -3352,6 +3354,7 @@ de: closed_title: Erledigter Hinweis Nr. %{note_name} hidden_title: Versteckter Hinweis Nr. %{note_name} description_when_author_is_deleted: gelöscht + description_when_there_is_no_opening_comment: unbekannt event_opened_by_html: Erstellt von %{user} %{time_ago} event_opened_by_anonymous_html: Erstellt von anonym %{time_ago} event_commented_by_html: Kommentar von %{user} %{time_ago} @@ -3591,6 +3594,8 @@ de: ninth: neunte tenth: zehnte time: Zeit + download: Route als GeoJSON herunterladen + filename: route query: node: Knoten way: Linie diff --git a/config/locales/en.yml b/config/locales/en.yml index 3a82aab39..b56fb6410 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2905,6 +2905,7 @@ en: confirmed: Confirmed suspended: Suspended deleted: Deleted + name_or_email: Name or Email ip_address: IP Address search: Search page: @@ -3103,6 +3104,7 @@ en: closed_title: "Resolved note #%{note_name}" hidden_title: "Hidden note #%{note_name}" description_when_author_is_deleted: "deleted" + description_when_there_is_no_opening_comment: "unknown" event_opened_by_html: "Created by %{user} %{time_ago}" event_opened_by_anonymous_html: "Created by anonymous %{time_ago}" event_commented_by_html: "Comment from %{user} %{time_ago}" diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 4cbc7734f..e3239f502 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -370,6 +370,13 @@ eo: havaĵo. consider_pd_why: Kiel vi volus, ke miaj kontribuaĵoj estu publikaj? confirm: Konfirmi + create: + successfully_declared: Vi sukcese deklaris, por ke viaj redaktoj estu en la + publika havaĵo. + already_declared: Vi jam deklaris, por ke viaj redaktoj estu en la publika + havaĵo. + did_not_confirm: Vi malkonsentis, por ke viaj redaktoj estu en la publika + havaĵo. browse: deleted_ago_by_html: Forigita %{time_ago} de %{user} edited_ago_by_html: Redaktita %{time_ago} de %{user} @@ -1009,6 +1016,7 @@ eo: bridleway: Ĉevalvojo bus_guideway: AÅ­tobus-trako bus_stop: Haltejo aÅ­tobusa + busway: AÅ­tobusa vojo construction: Vojo konstruata corridor: Koridoro crossing: Trapasejo @@ -1579,6 +1587,7 @@ eo: reports: Raportoj last_updated: Laste aktualigita last_updated_time_ago_user_html: '%{time_ago} de %{user}' + reporting_users: Raportantaj uzantoj reports_count: one: '%{count} raporto' other: '%{count} raportoj' @@ -1617,6 +1626,8 @@ eo: reopened: Problemo estas malfermita comments: comment_from_html: Komento fare de %{user_link} je %{comment_created_at} + reassign_to_moderators: Reasigni problemon al kontrolantoj + reassign_to_administrators: Reasigni problemon al administrantoj reports: reported_by_html: Raportita kiel %{category} fare de %{user} je %{updated_at} helper: @@ -1692,6 +1703,13 @@ eo: communities: Komunumoj learn_more: Ekscii pli more: Pli + offline_flash: + osm_offline: La OpenStreetMap-datumbazo estas nuntempe eksterreta pro necesaj + laboroj de prizorgado. + osm_read_only: La OpenStreetMap-datumbazo estas nuntempe en nurlega reĝimo pro + necesaj laboroj de prizorgado. + expected_restore_html: La servoj probable estos restarigitaj je %{time}. + announcement: Vi povas legi la afiŝon tie ĉi. user_mailer: diary_comment_notification: description: 'OpenStreetMap: taglibra afiŝo %{id}' @@ -2729,10 +2747,12 @@ eo: write_prefs: modifi preferojn de uzanto write_diary: afiŝi en taglibro kaj komenti write_api: redakti la mapon + write_changeset_comments: komenti ŝanĝarojn read_gpx: legi privatajn GPS-spurojn write_gpx: alŝuti GPS-spurojn write_notes: modifi rimarkojn write_redactions: Redakti map-datumojn + write_blocks: krei kaj nuligi blokadojn al uzantoj read_email: legi retpoŝtan adreson de uzanto consume_messages: legi, ŝanĝi staton kaj forigi mesaĝojn de uzanto send_messages: sendi privatajn mesaĝojn al aliaj uzantoj @@ -2839,6 +2859,7 @@ eo: my notes: Miaj rimarkoj my messages: Mesaĝoj my profile: Profilo + my_account: Mia konto my comments: Miaj komentoj my_preferences: Preferoj my_dashboard: Panelo @@ -2916,6 +2937,16 @@ eo: show: title: Uzantoj heading: Uzantoj + select_status: Elekti staton + states: + pending: pritraktata + active: aktiva + confirmed: konfirmita + suspended: blokita + deleted: forigita + name_or_email: Nomo aÅ­ retpoŝta adreso + ip_address: IP-adreso + search: Serĉi page: found_users: one: '%{count} trovita uzanto' @@ -2929,8 +2960,8 @@ eo: comments: index: heading_html: Komentoj de %{user} - changesets: pri ŝanĝaroj - diary_entries: pri taglibraj afiŝoj + changesets: Ŝanĝaroj + diary_entries: Taglibroj no_comments: Neniu komento changeset_comments: index: @@ -2947,8 +2978,8 @@ eo: when: Kiam comment: Komento suspended: - title: Konto haltigita - heading: Konto haltigita + title: Konto blokita + heading: Konto blokita support: subtena teamo automatically_suspended: BedaÅ­rinde via konto estas aÅ­tomate blokita pro suspektinda agado. @@ -3116,6 +3147,8 @@ eo: open_title: 'Nesolvita rimarko #%{note_name}' closed_title: 'Solvita rimarko #%{note_name}' hidden_title: 'Kaŝita rimarko #%{note_name}' + description_when_author_is_deleted: forigita + description_when_there_is_no_opening_comment: nekonata event_opened_by_html: Kreita de %{user} %{time_ago} event_opened_by_anonymous_html: Anonime kreita %{time_ago} event_commented_by_html: Komento de %{time_ago} de %{user} @@ -3353,6 +3386,8 @@ eo: ninth: 9-an tenth: 10-an time: Tempo + download: Elŝuti kurson kiel GeoJSON + filename: kurso query: node: Nodo way: Linio @@ -3367,6 +3402,9 @@ eo: show_address: Montri adreson query_features: Informoj pri objektoj centre_map: Centrigi mapon ĉi tien + home: + marker_title: Mia hejmloko + not_set: Hejmloko ne estas agordita por via konto redactions: edit: heading: Redakti korekton diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 1f8595fb3..1fb42e2e2 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -204,6 +204,7 @@ fr: allow_write_prefs: modifier les préférences de l’utilisateur allow_write_diary: créer des entrées du journal et des commentaires allow_write_api: modifier la carte + allow_write_changeset_comments: commenter les changements allow_read_gpx: lire ses traces GPS privées allow_write_gpx: téléverser des traces GPS allow_write_notes: modifier les notes diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 4e4c627e1..205d37635 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -263,9 +263,11 @@ gl: accounts: show: title: Editar a conta + my_account: A miña conta current email address: Enderezo de correo electrónico actual external auth: Autenticación externa openid: + link: https://wiki.openstreetmap.org/wiki/OpenID link text: que é isto? contributor terms: heading: Termos do colaborador @@ -275,7 +277,11 @@ gl: do colaborador. agreed_with_pd: Tamén declaraches que consideras que as túas edicións pertencen ó dominio público. + link: https://osmfoundation.org/wiki/Licence/Contributor_Terms link text: que é isto? + not_agreed_with_pd: Non declaraches que consideras que as túas edicións pertencen + ó dominio público. + pd_link_text: declárao save changes button: Gardar as modificacións delete_account: Borrar a conta... go_public: @@ -362,7 +368,19 @@ gl: terms_declined_url: https://wiki.openstreetmap.org/wiki/Contributor_Terms_Declined pd_declarations: show: + title: Considerar as miñas contribucións de dominio público + consider_pd: Considero que as miñas contribucións son de dominio público + consider_pd_why: Por que querería que as miñas contribucións sexan de dominio + público? consider_pd_why_url: https://osmfoundation.org/wiki/Licence_and_Legal_FAQ/Why_would_I_want_my_contributions_to_be_public_domain + confirm: Confirmar + create: + successfully_declared: Declaraches que consideras que as túas edicións pertencen + ao dominio público. + already_declared: Xa declaraches que consideras que as túas edicións pertencen + ao dominio público. + did_not_confirm: Non confirmaches que consideras que as túas edicións pertencen + ao dominio público. browse: deleted_ago_by_html: Borrado %{time_ago} por %{user} edited_ago_by_html: Editado %{time_ago} por %{user} @@ -2038,7 +2056,7 @@ gl: failure: Non foi posíbel actualizar o perfil. sessions: new: - tab_title: Acceder ao sistema + tab_title: Iniciar a sesión login_to_authorize_html: Inicia sesión no OpenStreetMap para acceder a %{client_app_name}. email or username: Enderezo de correo electrónico ou nome de usuario password: Contrasinal @@ -2799,6 +2817,7 @@ gl: write_gpx: Subir pistas GPS write_notes: Modificar notas write_redactions: Censurar datos do mapa + write_blocks: Crear e revogar bloqueos de usuarios read_email: Ver os enderezos de correo electrónico dos usuarios consume_messages: Ver, actualizar o estado e borrar mensaxes dos usuarios send_messages: Enviar mensaxes privadas aos usuarios @@ -2907,6 +2926,7 @@ gl: my notes: As miñas notas do mapa my messages: As miñas mensaxes my profile: O meu perfil + my_account: A miña conta my comments: Os meus comentarios my_preferences: As miñas preferencias my_dashboard: O meu panel de control @@ -2987,6 +3007,16 @@ gl: show: title: Usuarios heading: Usuarios + select_status: Seleccionar estado + states: + pending: Pendente + active: Activo + confirmed: Confirmado + suspended: Suspendido + deleted: Borrado + name_or_email: Nome ou correo electrónico + ip_address: Enderezo IP + search: Procurar page: found_users: one: Atopouse %{count} usuario @@ -3191,6 +3221,7 @@ gl: closed_title: Nota resolta n.º %{note_name} hidden_title: Nota agochada n.º %{note_name} description_when_author_is_deleted: eliminado + description_when_there_is_no_opening_comment: descoñecido event_opened_by_html: Creado por %{user} %{time_ago} event_opened_by_anonymous_html: Creado por un usuario anónimo %{time_ago} event_commented_by_html: Comentario de %{user} %{time_ago} @@ -3426,6 +3457,8 @@ gl: ninth: 9.ª tenth: 10.ª time: Tempo + download: Descargar a ruta como GeoJSON + filename: ruta query: node: Nó way: Vía @@ -3440,6 +3473,9 @@ gl: show_address: Amosar enderezo query_features: Consultar elementos centre_map: Centrar o mapa aquí + home: + marker_title: Localización da miña casa + not_set: A localización da casa non está configurada para a túa conta redactions: edit: heading: Editar a censura diff --git a/config/locales/it.yml b/config/locales/it.yml index e027f941d..805b32b5f 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -308,7 +308,7 @@ it: accounts: show: title: Modifica profilo - my_account: Il mio profilo + my_account: La mia utenza current email address: Indirizzo email attuale external auth: Autenticazione esterna openid: @@ -2954,7 +2954,7 @@ it: my notes: Le mie note my messages: I miei messaggi my profile: Il mio profilo - my_account: Il mio profilo + my_account: La mia utenza my comments: I miei commenti my_preferences: Preferenze my_dashboard: La mia dashboard @@ -3042,6 +3042,7 @@ it: confirmed: Confermato suspended: Sospeso deleted: Cancellato + name_or_email: Nome o e-mail ip_address: Indirizzo IP search: Cerca page: @@ -3250,6 +3251,7 @@ it: closed_title: 'Nota risolta #%{note_name}' hidden_title: 'Nota nascosta #%{note_name}' description_when_author_is_deleted: cancellato + description_when_there_is_no_opening_comment: sconosciuto event_opened_by_html: Creata da %{user} %{time_ago} event_opened_by_anonymous_html: Creata da anonimo %{time_ago} event_commented_by_html: Commento da %{user} %{time_ago} @@ -3483,6 +3485,8 @@ it: ninth: 9ª tenth: 10ª time: Tempo + download: Scarica l'itinerario come GeoJson + filename: itinerario query: node: Nodo way: Percorso diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 6786b32f3..7d1d0c4de 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -2654,6 +2654,7 @@ ko: confirmed: 확인됨 suspended: 정지됨 deleted: 삭제됨 + name_or_email: 이름 또는 이메일 ip_address: IP 주소 search: 검색 page: @@ -2823,6 +2824,7 @@ ko: open_title: '해결되지 않은 참고 #%{note_name}' closed_title: '해결된 참고 #%{note_name}' hidden_title: '숨겨진 참고 #%{note_name}' + description_when_there_is_no_opening_comment: 알 수 없음 event_opened_by_html: '%{time_ago} %{user}님이 생성함' event_opened_by_anonymous_html: '%{time_ago} 익명의 사용자가 생성함' event_commented_by_html: '%{time_ago} %{user}님의 댓글' diff --git a/config/locales/lb.yml b/config/locales/lb.yml index 4e7eb351e..5f853bda6 100644 --- a/config/locales/lb.yml +++ b/config/locales/lb.yml @@ -2342,6 +2342,7 @@ lb: my notes: Meng Notizen my messages: Meng Messagen my profile: Mäi Profil + my_account: Mäi Benotzerkont my comments: Meng Bemierkungen my_preferences: Meng Benotzerastellungen my_dashboard: Meng Iwwersiichtssäit @@ -2396,6 +2397,7 @@ lb: active: Aktiv confirmed: Confirméiert deleted: Geläscht + name_or_email: Numm oder E-Mail ip_address: IP-Adress search: Sichen page: @@ -2497,6 +2499,7 @@ lb: closed_title: 'Geléisten Hiweis #%{note_name}' hidden_title: Verstoppt Notiz N° %{note_name} description_when_author_is_deleted: geläscht + description_when_there_is_no_opening_comment: onbekannt report: Dësen Hiweis mellen discussion: Diskussioun subscribe: Abonéieren @@ -2621,6 +2624,8 @@ lb: ninth: néngt tenth: zéngt time: Zäit + download: Streck als GeoJSON eroflueden + filename: Streck query: way: Wee relation: Relatioun diff --git a/config/locales/nl.yml b/config/locales/nl.yml index e647046a4..554a4f061 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -2763,8 +2763,8 @@ nl: niet te onderschijven, maar moet ze wel gezien hebben. settings_menu: account_settings: Accountinstellingen - oauth2_applications: OAuth 2 toepassingen - oauth2_authorizations: OAuth 2 autorisaties + oauth2_applications: OAuth 2-toepassingen + oauth2_authorizations: OAuth 2-autorisaties muted_users: Gedempte gebruikers auth_providers: openid_url: OpenID-URL diff --git a/config/locales/pl.yml b/config/locales/pl.yml index bc1c78f33..7541d4c9d 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -539,6 +539,7 @@ pl: start_rjs: feature_warning: Wczytywanie %{num_features} obiektów, może spowolnić lub zawiesić przeglądarkę. Wyświetlić te dane? + feature_error: 'Błąd przy ładowaniu obiektów: %{message}' load_data: Wczytaj dane loading: Wczytywanie... tag_details: @@ -1684,11 +1685,13 @@ pl: reports: Zgłoszenia last_updated: Ostatnia aktualizacja last_updated_time_ago_user_html: '%{time_ago} przez %{user}' + reporting_users: Raportowanie użytkowników reports_count: one: 1 zgłoszenie few: '%{count} zgłoszenia' many: '%{count} zgłoszeń' other: '%{count} zgłoszenia' + more_reporters: i jeszcze %{count} reported_item: Zgłoszony element states: ignored: Zignorowano @@ -1726,6 +1729,8 @@ pl: reopened: Status sprawy został ustawiony na „Otwarta” comments: comment_from_html: Komentarz od %{user_link} z %{comment_created_at} + reassign_to_moderators: Przydziel sprawę moderatorom + reassign_to_administrators: Przydziel sprawę administratorom reports: reported_by_html: Zgłoszone %{updated_at} jako %{category} przez %{user} helper: @@ -1806,6 +1811,13 @@ pl: communities: Społeczności learn_more: Dowiedz się więcej more: Więcej + offline_flash: + osm_offline: Baza danych OpenStreetMap jest w trybie offline na czas ważnych + zadań administracyjnych, które są w tym momencie wykonywane. + osm_read_only: Baza danych OpenStreetMap jest w trybie tylko do odczytu na czas + ważnych zadań administracyjnych, które są w tym momencie wykonywane. + expected_restore_html: Przywrócenie usług spodziewane jest w ciągu %{time}. + announcement: Ogłoszenie można przeczytać tutaj. user_mailer: diary_comment_notification: description: 'Wpis dziennika OpenStreetMap #%{id}' @@ -3121,6 +3133,10 @@ pl: show: title: Użytkownicy heading: Użytkownicy + select_status: Wybierz status + name_or_email: Nazwa lub e-mail + ip_address: Adres IP + search: Szukaj page: found_users: one: Znaleziono %{count} użytkownika @@ -3588,6 +3604,8 @@ pl: ninth: "9." tenth: "10." time: Czas + download: Pobierz trasę jako GeoJSON + filename: trasa query: node: Węzeł way: Linia @@ -3602,6 +3620,9 @@ pl: show_address: Pokaż adres query_features: Wyświetl dane obiektów centre_map: Wycentruj mapę tutaj + home: + marker_title: Położenie domu + not_set: Położenie domu nie jest ustawione w twoim profilu redactions: edit: heading: Edytuj poprawkę diff --git a/config/locales/ru.yml b/config/locales/ru.yml index ac27335ed..9c0c9daee 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -15,6 +15,7 @@ # Author: Anton Khorev # Author: Ashed # Author: Banonotit +# Author: Borealex # Author: BushmanK # Author: Butko # Author: CM3X @@ -113,6 +114,7 @@ # Author: XnL # Author: Yuri Nazarov # Author: Yurik +# Author: Yurina Tatiana # Author: Yuryleb # Author: Zverik # Author: Александр Сигачёв @@ -204,6 +206,7 @@ ru: allow_write_prefs: изменять пользовательские настройки allow_write_diary: создавать записи в дневнике и комментарии allow_write_api: редактировать карту + allow_write_changeset_comments: комментировать пакеты правок allow_read_gpx: читать частные GPS-треки allow_write_gpx: загружать GPS-треки allow_write_notes: исправлять заметки @@ -384,6 +387,7 @@ ru: accounts: show: title: Изменить учетную запись + my_account: Мой аккаунт current email address: Текущий адрес электронной почты external auth: 'Внешняя аутентификация:' openid: @@ -399,6 +403,9 @@ ru: в общественном достоянии. link: https://openstreetmap.org/wiki/RU:Open_Database_License/Contributor_Terms?uselang=ru link text: что это? + not_agreed_with_pd: Вы не заявили, что считаете свои правки находящимися в + общественном достоянии. + pd_link_text: объявить save changes button: Сохранить изменения delete_account: Удалить учётную запись… go_public: @@ -572,6 +579,7 @@ ru: start_rjs: feature_warning: Необходимо загрузить %{num_features} объектов, что может замедлить ваш браузер. Вы уверены, что хотите просмотреть эти данные? + feature_error: 'Не удалось загрузить объекты: %{message}' load_data: Загрузить данные loading: Загружается… tag_details: @@ -734,6 +742,8 @@ ru: nearby users: Другие ближайшие пользователи no nearby users: Пока нет других пользователей, которые признают, что занимаются составлением карты поблизости. + followed_changesets: пакеты правок + followed_diaries: дневники nearby_changesets: пакеты правок соседей nearby_diaries: дневники соседей diary_entries: @@ -2754,7 +2764,7 @@ ru: scopes: read_prefs: Прочитать настройки пользователя write_prefs: Изменить настройки пользователя - write_diary: Создавать записи в дневнике, комментировать и заводить друзей + write_diary: Создавать записи в дневнике и комментарии write_api: Изменить карту read_gpx: Читать частные GPS-треки write_gpx: Загрузить GPS-треки @@ -2856,6 +2866,7 @@ ru: my notes: Мои заметки my messages: Мои сообщения my profile: Мой профиль + my_account: Мой аккаунт my comments: Мои комментарии my_preferences: Мои предпочтения my_dashboard: Мой пульт @@ -2921,9 +2932,11 @@ ru: heading: Пользователи states: pending: В ожидании + active: Активен confirmed: Подтверждено suspended: Приостановлено deleted: Удалено + name_or_email: Имя или адрес эл. почты ip_address: IP-адрес search: Поиск page: @@ -2935,9 +2948,13 @@ ru: summary_no_ip_html: '%{name} создан %{date}' comments: index: + heading_html: Комментарии пользователя %{user} + changesets: Пакеты правок diary_entries: Записи в дневнике + no_comments: Нету комментариев changeset_comments: page: + changeset: Пакет правок when: Когда comment: Комментарий diary_comments: @@ -2945,6 +2962,8 @@ ru: title: Комментарии к записям в дневнике, добавленные пользователем %{user} page: post: Сообщение + when: Когда + comment: Комментарий suspended: title: Учётная запись приостановлена heading: Учётная запись приостановлена @@ -3363,6 +3382,7 @@ ru: query_features: Что здесь? centre_map: Центрировать карту home: + marker_title: Мой домашний адрес not_set: Установка места нахождения не установлена для вашей учётной записи redactions: edit: diff --git a/config/locales/skr-arab.yml b/config/locales/skr-arab.yml index bcc03a0a2..2f2a9dee3 100644 --- a/config/locales/skr-arab.yml +++ b/config/locales/skr-arab.yml @@ -4,6 +4,7 @@ # Author: Ajeje Brazorf # Author: Saraiki # Author: Sayam Asjad +# Author: Umar Shahid --- skr-arab: html: @@ -1422,6 +1423,7 @@ skr-arab: eighth: ٨واں ninth: ٩واں tenth: ١٠واں + download: روٹ کوں GeoJSON دے طور تے ڈاؤن لوڈ کرو۔ redactions: show: confirm: بھلا تہاکوں Ù¾Ú© ہے؟ diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 74388e3bc..d5286ff01 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -1708,7 +1708,7 @@ sl: ste jo dodali. Opomba je v bližini %{place}.' commented_note_html: '%{commenter} je spet aktiviral_a opombo na zemljevidu, ki ste jo dodali. Opomba je v bližini %{place}.' - details: Več podatkov o opombi lahko najdete na %{url}. + details: Več podatkov o opombi je na voljo na %{url}. details_html: Na opombo lahko odgovorite ali izveste več o njej na %{url}. changeset_comment_notification: description: Nabor sprememb OpenStreetMap Å¡t. %{id} @@ -2918,6 +2918,7 @@ sl: status: Stanje navigation: block: 'Blokiraj #%{id}' + new_block: Novo blokiranje user_mutes: index: title: UtiÅ¡ani uporabniki diff --git a/config/locales/sr.yml b/config/locales/sr.yml index c23d9b28a..bdd30c03e 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -2204,6 +2204,7 @@ sr: heading: Корисници states: deleted: Обрисано + name_or_email: Име или имејл ip_address: IP адреса search: Претрага page: @@ -2333,6 +2334,7 @@ sr: closed_title: Решена белешка бр. %{note_name} hidden_title: Скривена белешка бр. %{note_name} description_when_author_is_deleted: обрисано + description_when_there_is_no_opening_comment: непознато event_opened_by_html: Направио %{user} %{time_ago} report: пријави ову белешку anonymous_warning: Ова белешка садржи коментаре анонимних корисника које би diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 52d7cb2a2..cfcbad6f9 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -138,6 +138,7 @@ sv: allow_write_prefs: ändra deras användaralternativ allow_write_diary: skapa dagboksinlägg och kommentarer allow_write_api: ändra kartan + allow_write_changeset_comments: kommentar pÃ¥ ändringsuppsättning allow_read_gpx: läs deras privata GPS-spÃ¥r allow_write_gpx: ladda upp GPS-spÃ¥r allow_write_notes: ändra anteckningar @@ -292,6 +293,7 @@ sv: accounts: show: title: Redigera konto + my_account: Mitt konto current email address: Nuvarande e-postadress external auth: Extern autentisering openid: @@ -305,6 +307,9 @@ sv: agreed_with_pd: Du har ocksÃ¥ förklarat att du anser att dina redigeringar är inom Public Domain. link text: vad är detta? + not_agreed_with_pd: Du har inte förklarat att du anser att dina redigeringar + är inom Public Domain. + pd_link_text: förklara save changes button: Spara ändringar delete_account: Radera konto... go_public: @@ -389,6 +394,15 @@ sv: terms_declined_html: Vi beklagar att du bestämt dig för att inte acceptera de nya användarvillkoren. För mer information, se %{terms_declined_link}. terms_declined_link: denna wikisida + pd_declarations: + show: + title: Anse att mina bidrag är i public domain + consider_pd: Jag anser mina bidrag vara i public domain + consider_pd_why: Varför skulle jag vilja ha mina bidrag i public domain? + confirm: Bekräfta + create: + successfully_declared: Du har förklarat att du anser att dina redigeringar + är inom public domain. browse: deleted_ago_by_html: Raderades %{time_ago} av %{user} edited_ago_by_html: Redigerades %{time_ago} av %{user} @@ -2893,6 +2907,7 @@ sv: my notes: Mina kartanteckningar my messages: Mina meddelanden my profile: Min profil + my_account: Mitt konto my comments: Mina kommentarer my_preferences: Mina alternativ my_dashboard: Min kontrollpanel @@ -2972,6 +2987,15 @@ sv: show: title: Användare heading: Användare + select_status: Välj status + states: + pending: PÃ¥gÃ¥ende + active: Aktiv + confirmed: Bekräftad + suspended: Uppskjutet + deleted: Raderad + ip_address: IP-adress + search: Sök page: found_users: one: '%{count} användare hittade' @@ -3180,6 +3204,7 @@ sv: closed_title: 'Avklarad anteckning #%{note_name}' hidden_title: 'Dold anteckning #%{note_name}' description_when_author_is_deleted: raderad + description_when_there_is_no_opening_comment: okänd event_opened_by_html: Skapades av %{user} %{time_ago} event_opened_by_anonymous_html: Skapades av anonym %{time_ago} event_commented_by_html: Kommenterades frÃ¥n %{user} %{time_ago} @@ -3408,6 +3433,8 @@ sv: ninth: 9:e tenth: 10:e time: Tid + download: Ladda ner rutt som GeoJSON + filename: rutt query: node: Nod way: Sträcka @@ -3422,6 +3449,9 @@ sv: show_address: Visa adress query_features: Undersök kartobjekt centre_map: Centrera kartan här + home: + marker_title: Min hemort + not_set: Hemort har inte angetts för ditt konto redactions: edit: heading: Redigera maskering diff --git a/config/locales/th.yml b/config/locales/th.yml index 2c244ac8f..6b5b396b1 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -242,6 +242,7 @@ th: accounts: show: title: แก้ไขบัญชี + my_account: บัญชีของฉัน current email address: ที่อยู่อีเมลปัจจุบัน external auth: การยืนยันตัวตนด้วยบริการภายนอก openid: @@ -253,6 +254,7 @@ th: review link text: โปรดเข้าลิงก์นี้ตามความสะดวกของคุณเพื่อตรวจสอบและยอมรับข้อกำหนดของผู้ร่วมให้ข้อมูลใหม่ agreed_with_pd: คุณยังได้ประกาศด้วยว่า คุณถือว่าการแก้ไขของคุณถือว่าเป็นสาธารณสมบัติ link text: นี่คืออะไร? + pd_link_text: ประกาศ save changes button: บันทึกการเปลี่ยนแปลง delete_account: ลบบัญชี... go_public: @@ -300,6 +302,7 @@ th: contributor_terms_explain: ข้อตกลงนี้ใช้บังคับกับข้อกำหนดสำหรับการมีส่วนร่วมในปัจจุบันและในอนาคตของคุณ read_ct: ฉันได้อ่านและยอมรับเงื่อนไขของผู้มีส่วนร่วมให้ข้อมูลข้างต้นแล้ว read_tou: ข้าพเจ้าได้อ่านและเห็นด้วยในข้อกำหนดการใช้งาน + informal_translations: การแปลแบบไม่เป็นทางการ continue: ถัดไป cancel: ยกเลิก you need to accept or decline: กรุณาตรวจทานและเลือกยอมรับหรือไม่ยอมรับข้อกำหนดของผู้ร่วมให้ข้อมูลเพื่อไปต่อ @@ -310,6 +313,9 @@ th: rest_of_world: พื้นที่อื่น ๆ ในโลก update: terms accepted: ขอบคุณสำหรับการตอบรับเงื่อนไขผู้ร่วมให้ข้อมูล! + pd_declarations: + show: + confirm: ยืนยัน browse: deleted_ago_by_html: ลบเมื่อ %{time_ago} โดย %{user} edited_ago_by_html: แก้ไขเมื่อ %{time_ago} โดย %{user} @@ -961,6 +967,8 @@ th: wayside_shrine: ศาลเจ้าริมทาง wreck: ซากปรักหักพัง "yes": สถานที่ประวัติศาสตร์ + information: + office: สำนักงานบริการนักท่องเที่ยว junction: "yes": ทางแยก landuse: @@ -1373,6 +1381,13 @@ th: building_passage: ทางลอดใต้อาคาร culvert: ท่อระบายน้ำ "yes": อุโมงค์ + water: + lake: ทะเลสาบ + pond: สระน้ำ + reservoir: อ่างเก็บน้ำ + lagoon: ลากูน + wastewater: น้ำเสีย + oxbow: ทะเลสาบรูปแอก waterway: artificial: ทางน้ำที่มนุษย์สร้าง boatyard: ที่จอดเรือ @@ -1787,6 +1802,11 @@ th: เพิ่มข้อมูล หรือกระทำการให้เกิดสิ่งอื่นใดใหม่ขึ้นต่องานที่มีนี้ ท่านสามารถแจกจ่ายได้แต่เพียงภายใต้สัญญาอนุญาตเดียวกันเท่านั้น โปรดดู%{copyright_license_link}สำหรับลายละเอียดเพิ่มเติม legal_title: ข้อกำหนดทางกฎหมาย + legal_1_1_terms_of_use: ข้อกำหนดการใช้งาน + legal_1_1_aup: นโยบายการใช้งานที่ยอมรับได้ + legal_1_1_privacy_policy: นโยบายความเป็นส่วนตัว + legal_2_1_html: โปรดไปที่ %{contact_the_osmf_link} หากคุณมีปัญหาหรือข้อสงสัยเกี่ยวกับการอนุญาตให้ใช้งาน + ลิขสิทธิ์ หรือข้อสงสัยด้านกฎหมายอื่น ๆ partners_title: องค์กรพันธมิตร copyright: title: ลิขสิทธิ์และสัญญาอนุญาต @@ -1802,6 +1822,7 @@ th: native_link: รุ่นภาษาTHIS_LANGUAGE_NAME_HERE mapping_link: เริ่มการทำแผนที่ legal_babble: + introduction_1_open_data: ข้อมูลเปิดเผย introduction_2_html: คุณสามารถคัดลอก แจกจ่าย ถ่ายทอด และดัดแปลงข้อมูลของเราได้อย่างเสรี ตราบใดที่คุณให้อ้างอิงเครดิต OpenStreetMap และผู้ร่วมให้ข้อมูล ถ้าคุณแก้ไข หรือสร้างข้อมูลต่อจากข้อมูลของเรา คุณสามารถเผยแพร่ผลลัพธ์ภายใต้สัญญาเดิมเท่านั้น @@ -1810,6 +1831,7 @@ th: credit_1_html: |- เราจำเป็นต้องให้ท่านแสดงที่มาหรือคำขอบคุณแก่ “© ผู้ร่วมสร้างสรรค์ OpenStreetMap ”. + credit_3_attribution_guidelines: แนวทางการระบุแหล่งที่มา attribution_example: alt: ตัวอย่างการอ้างอิง OpenStreetMap บนหน้าเว็บ title: ตัวอย่างการอ้างอิง @@ -1823,11 +1845,23 @@ th: contributors_at_stadt_wien: เมืองเวียนนา contributors_at_land_vorarlberg: แลนด์ ฟอร์อาร์ลแบร์ค contributors_at_cc_by_at_with_amendments: CC BY AT with amendments + contributors_cz_czechia: เช็กเกีย + contributors_fi_finland: ฟินแลนด์ + contributors_fr_france: ฝรั่งเศส + contributors_hr_croatia: โครเอเชีย + contributors_si_slovenia: สโลวีเนีย + contributors_si_gu: หน่วยงานสำรวจและจัดทำแผนที่ + contributors_si_mkgp: กระทรวงการเกษตร ป่าไม้ และอาหาร + contributors_es_credit_html: '%{spain}: ประกอบด้วยข้อมูลที่มาจากสถาบันภูมิศาสตร์แห่งชาติสเปน + (%{ign_link}) และระบบการทำแผนที่แห่งชาติสเปน (%{scne_link}) ซึ่งได้รับอนุญาตให้ทำซ้ำภายใต้สัญญา + %{cc_by_link}' + contributors_es_spain: สเปน contributors_footer_2_html: การรวมข้อมูลใน OpenStreetMap ไม่ได้หมายความว่าผู้ให้บริการข้อมูลดั้งเดิมจะรับรอง OpenStreetMap รับประกัน หรือรับผิดชอบใด ๆ infringement_title_html: การละเมิดลิขสิทธิ์ infringement_1_html: ผู้ร่วมให้ข้อมูล OSM จะถูกเตือนไม่ให้เพิ่มข้อมูลจากแหล่งข้อมูลที่มีลิขสิทธิ์ (เช่น Google Maps หรือแผนที่แบบพิมพ์) โดยไม่ได้รับอนุญาตอย่างชัดเจนจากเจ้าของลิขสิทธิ์ + trademarks_title: เครื่องหมายการค้า index: js_1: ท่านกำลังใช้เบราว์เซอร์ที่ไม่รองรับจาวาสคริปต์ หรือท่านปิดใช้งานจาวาสคริปต์ js_2: OpenStreetMap ใช้จาวาสคริปต์ในการแสดงแผนที่ @@ -1922,6 +1956,9 @@ th: taxiway: ทางขับเครื่องบิน apron: โรงซ่อมบำรุงเครื่องบิน admin: ขอบเขตการปกครอง + capital: เมืองหลวง + city: เมือง + orchard: สวนผลไม้ forest: ป่า wood: ไม้ golf: สนามกอล์ฟ @@ -1934,18 +1971,25 @@ th: heathland: ทุ่งไม้พุ่ม lake: ทะเลสาบ reservoir: อ่างเก็บน้ำ + glacier: ธารน้ำแข็ง + wetland: พื้นที่ชุ่มน้ำ farm: ไร่นา brownfield: พื้นที่อุตสาหกรรมเดิม cemetery: สุสาน allotments: ที่ดินแบ่งใช้ pitch: ลานกีฬา centre: ศูนย์กีฬา + beach: ชายหาด reserve: พื้นที่สงวนธรรมชาติ military: เขตทหาร school: โรงเรียน university: มหาวิทยาลัย + hospital: โรงพยาบาล building: อาคารสำคัญ station: สถานีรถไฟ + railway_halt: ที่หยุดรถไฟ + subway_station: สถานีรถไฟใต้ดิน + tram_stop: ที่หยุดรถราง summit: ยอดเขา peak: ยอดเขา tunnel: เส้นประ = อุโมงค์ @@ -1953,7 +1997,9 @@ th: private: พื้นที่ส่วนบุคคล destination: การเข้าถึงที่จุดปลายทาง construction: ถนนกำลังก่อสร้าง + bus_stop: ป้ายหยุดรถประจำทาง bicycle_shop: ร้านขายและเช่าจักรยาน + bicycle_rental: บริการให้เช่าจักรยาน bicycle_parking: ที่จอดจักรยาน toilets: ห้องน้ำ welcome: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index ac8c50251..6834d54ca 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -24,6 +24,7 @@ # Author: Katpatuka # Author: Khalvar # Author: Kumkumuk +# Author: Leo # Author: LuCKY # Author: Makina88 # Author: Mavrikant @@ -137,7 +138,7 @@ tr: support_url: Destek Bağlantısı allow_read_prefs: kullanıcı tercihlerini okuyun allow_write_prefs: kullanıcı tercihlerini değiştir - allow_write_diary: günlük girdiler, yorumlar oluşturun ve arkadaş edinin + allow_write_diary: günlük kayıtları ve yorumları oluşturun allow_write_api: haritayı değiştir allow_read_gpx: özel GPS izlerini oku allow_write_gpx: GPS izlerini yükle diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 07a7b690a..80545d79b 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -135,6 +135,7 @@ uk: allow_write_prefs: змінювати налаштування allow_write_diary: створювати записи у щоденнику та залишати коментарі allow_write_api: змінювати мапу + allow_write_changeset_comments: коментувати набори змін allow_read_gpx: отримувати приватні GPS-треки. allow_write_gpx: надсилати GPS-треки на сервер allow_write_notes: змінювати нотатки @@ -317,6 +318,7 @@ uk: accounts: show: title: Редагувати обліковий запис + my_account: Обліковий запис current email address: Поточна адреса електронної пошти external auth: Стороння автентифікація openid: @@ -332,6 +334,8 @@ uk: Надбанням. link: https://wiki.openstreetmap.org/wiki/Uk:Open_Database_License/Contributor_Terms link text: що це? + not_agreed_with_pd: Ви не заявили, що ви вважаєте свій внесок Суспільним Надбанням. + pd_link_text: заявляю save changes button: Зберегти зміни delete_account: Видалити обліковий запис… go_public: @@ -417,7 +421,18 @@ uk: terms_declined_url: https://wiki.openstreetmap.org/wiki/Uk:Contributor_Terms_Declined pd_declarations: show: + title: Вважайте, що мій внесок є Суспільним Надбанням + consider_pd: Я вважаю, що мій внесок є суспільним надбанням + consider_pd_why: Чому я мав(ла) би хотіти, щоб мій внесок став Суспільним + Надбанням? consider_pd_why_url: https://wiki.openstreetmap.org/wiki/Uk:Чому_я_хочу,_щоб_мої_внески_були_суспільним_надбанням + confirm: Підтвердити + create: + successfully_declared: Ви заявили, що вважаєте, що ваші правки є Суспільним + Надбанням. + already_declared: Ви вже заявили, що вважаєте, що ваші правки є Суспільним + Надбанням. + did_not_confirm: Ви не підтвердили, що вважаєте свої правки Суспільним Надбанням. browse: deleted_ago_by_html: Вилучив(ла) %{time_ago} %{user} edited_ago_by_html: Змінено %{user} %{time_ago} @@ -1069,6 +1084,7 @@ uk: bridleway: Дорога для їзди верхи bus_guideway: Рейковий автобус bus_stop: Автобусна зупинка + busway: Дорога для автобусів construction: Будівництво автомагістралі corridor: Коридор crossing: Перехід @@ -1641,6 +1657,7 @@ uk: reports: Скарги last_updated: Останнє оновлення last_updated_time_ago_user_html: '%{user} %{time_ago}' + reporting_users: Повідомлення про користувачів reports_count: one: '%{count} Скарга' few: '%{count} Скарги' @@ -1683,6 +1700,8 @@ uk: reopened: Статус проблеми був змінений на 'Відкрито' comments: comment_from_html: Коментар від %{user_link}, %{comment_created_at} + reassign_to_moderators: Перепризначити звернення Модераторам + reassign_to_administrators: Перепризначити звернення Адміністраторам reports: reported_by_html: Повідомлено як %{category}, %{user}, %{updated_at} helper: @@ -1761,6 +1780,13 @@ uk: communities: Спільноти learn_more: Докладніше more: Більше + offline_flash: + osm_offline: База даних OpenStreetMap наразі працює в режимі офлайн, поки проводяться + роботи з технічного обслуговування. + osm_read_only: База даних OpenStreetMap наразі працює в режимі тільки для читання, + поки проводяться роботи з технічного обслуговування. + expected_restore_html: Очікується, що роботу буде відновлено через %{time}. + announcement: Ознайомитися з оголошенням можна тут. user_mailer: diary_comment_notification: description: 'Запис у щоденнику OpenStreetMap #%{id}' @@ -2097,7 +2123,7 @@ uk: failure: Неможливо зберегти оновлення профілю. sessions: new: - tab_title: Ласкаво просимо + tab_title: Вхід login_to_authorize_html: Увійдіть до OpenStreetMap, щоб отримати доступ до %{client_app_name}. email or username: Ел. пошта або прізвисько password: Пароль @@ -2381,6 +2407,8 @@ uk: not_public_description_html: 'Ви не можете більше анонімно редагувати мапу. Ви можете зробити ваші редагування загальнодоступними тут: %{user_page}.' user_page_link: сторінка учасника + anon_edits_html: '%{link}' + anon_edits_link: https://wiki.openstreetmap.org/wiki/Uk:Анонімне_редагування anon_edits_link_text: З’ясувати в чому справа. edit: id_not_configured: iD не був налаштований @@ -2783,8 +2811,8 @@ uk: погоджуватись, але ви повинні переглянути їх. settings_menu: account_settings: Налаштування облікового запису - oauth2_applications: застосунки OAuth 2 - oauth2_authorizations: авторизації OAuth 2 + oauth2_applications: Застосунки OAuth 2 + oauth2_authorizations: Авторизації OAuth 2 muted_users: Стишені учасники auth_providers: openid_url: OpenID URL @@ -2838,10 +2866,12 @@ uk: write_prefs: Змінювати налаштування write_diary: Створювати записи у щоденнику та залишати коментарі write_api: Змінювати мапу + write_changeset_comments: Коментувати набори змін read_gpx: Отримувати приватні GPS-треки write_gpx: Завантажувати GPS-треки write_notes: Змінювати нотатки write_redactions: Виконувати очищення даних + write_blocks: Створювати та скасовувати блокування користувачів read_email: Отримувати адресу е-пошти consume_messages: Прочитати, оновити статус та видалити повідомлення користувача send_messages: Надіслати приватне повідомлення іншим користувачам @@ -2893,7 +2923,7 @@ uk: title: Авторизовані застосунки application: Застосунок permissions: Дозволи - last_authorized: Останній авторизований + last_authorized: В останнє авторизовано no_applications_html: У вас ще немає застосунків авторизованих через %{oauth2}. application: revoke: Відкликати доступ @@ -2953,6 +2983,7 @@ uk: my notes: Мої нотатки my messages: Повідомлення my profile: Профіль + my_account: Обліковий запис my comments: Мої коментарі my_preferences: Вподобання my_dashboard: Інфо панель @@ -3035,6 +3066,16 @@ uk: show: title: Учасники heading: Учасники + select_status: Обрати статус + states: + pending: В очікуванні + active: Активний + confirmed: Підтверджено + suspended: Призупинено + deleted: Вилучено + name_or_email: Імʼя або електронна пошта + ip_address: IP-адреса + search: Пошук page: found_users: one: знайдено %{count} користувача @@ -3254,6 +3295,8 @@ uk: open_title: 'Неопрацьована нотатка #%{note_name}' closed_title: 'Опрацьована нотатка #%{note_name}' hidden_title: 'Прихована нотатка #%{note_name}' + description_when_author_is_deleted: вилучено + description_when_there_is_no_opening_comment: невідомо event_opened_by_html: Створив(ла) %{user} %{time_ago} event_opened_by_anonymous_html: Створено анонімом %{time_ago} event_commented_by_html: Коментар від %{user} %{time_ago} @@ -3494,6 +3537,8 @@ uk: ninth: 9й tenth: 10й time: Час + download: Завантажити маршрут як GeoJSON + filename: маршрут query: node: Точка way: Лінія @@ -3508,6 +3553,9 @@ uk: show_address: Показати адресу query_features: Отримати об’єкти centre_map: Центрувати мапу тут + home: + marker_title: Моє розташування + not_set: Для вашого облікового запису не вказано його розташування redactions: edit: heading: Змінити редакцію diff --git a/config/locales/xmf.yml b/config/locales/xmf.yml index 0e9def5d5..791b4d8af 100644 --- a/config/locales/xmf.yml +++ b/config/locales/xmf.yml @@ -19,14 +19,14 @@ xmf: create: კომენტარი diary_entry: create: გუმობჟინაფა - update: გოახალაფა + update: მოახალება issue_comment: create: კომენტარიშ გეძინა message: create: ჯღონუა oauth2_application: create: რეგისტრაცია - update: გოახალაფა + update: მოახალება redaction: create: მიშათინუაშ გოჭყაფა update: მიშათინუაშ ჩუალა @@ -37,6 +37,10 @@ xmf: create: ბლოკირაფაშ გოჭყაფა update: ბლოკირაფაშ გოახალაფა activerecord: + errors: + models: + user_mute: + is_already_muted: უკვე აკორანგვილი რე models: acl: ხემეჭირნაფაშ კონტროლიშ ერკებული changeset: თირაფეფიშ პაკეტი @@ -50,6 +54,7 @@ xmf: message: გინაფა node: ჭურჭული node_tag: ჭურჭულიშ ხინტკი + note: ხვილაფა old_node: ჯვეში ჭურჭული old_node_tag: ჭურჭულიშ ჯვეში ხინტკი old_relation: ჯვეში ურთიართობა @@ -83,6 +88,7 @@ xmf: allow_write_diary: დღარეფიშ დინნაჭარეფიშ გოჭყაფა, კომენტირაფა დო მაჸალეეფიშ გეძინა allow_write_api: რუკაშ თირუა + allow_write_changeset_comments: თირუეფიშ პაკეტეფიშ კომენტირება allow_read_gpx: კერზო GPS-ტრეკეფიშ კითხირი allow_write_gpx: GPS-ტრეკეფიშ ეხარგუა allow_write_notes: მოღანკუეფიშ მიშათინუა @@ -259,8 +265,27 @@ xmf: retain_email: თქვან ელ-ფოშტა დიჩუალუაფუ. confirm_delete: დასურო გონებჷნანო? cancel: გოუქვაფა + terms: + show: + title: აპიჯალეფი + heading: წოროხანდაშ აპიჯალეფი + heading_ct: წოროხანდაშ აპიჯალეფი + continue: გაგჷნძორაფა + cancel: გოუქვაფა + legale_names: + france: საფრანგეთი + italy: იტალია + rest_of_world: დოსკილადირი მოსოფელი + terms_declined_flash: + terms_declined_link: თენა რე ვიკი ხასჷლა + pd_declarations: + show: + confirm: დოდასურება browse: + deleted_ago_by_html: დილასჷ %{time_ago} მახვარებუქ %{user} + edited_ago_by_html: დარედაქტირჷ %{time_ago} მახვარებუქ %{user} version: ვერსია + redacted_version: ვერსიაშ რედაქტირაფა in_changeset: თირაფეფიშ პაკეტი anonymous: ანონიმი no_comment: (უკომენტარე) @@ -334,6 +359,7 @@ xmf: wikimedia_commons_link: ელემენტი %{page} ვიკიოწკარუეს telephone_link: რეკუა %{phone_number} colour_preview: ფერი %{colour_value} გიწოთოლორაფა + email_link: ელექტრონული ფოშტა %{email} query: title: მუ რე თაქ? introduction: უახოლაში ობიექტეფიშ ოგორალო ქეგუნჭირით რუკა. @@ -347,6 +373,8 @@ xmf: title_html: 'ღოზიშ ისტორია: %{name}' relation: title_html: 'ურთიართობაშ ისტორია: %{name}' + actions: + view_redacted_data: რედაქტირებული მუნაჩემეფშა გინოჯინა changeset_comments: feeds: comment: @@ -384,6 +412,11 @@ xmf: join_discussion: გემშართით სისტემაშა, თიშენ ნამჷ-და, სხუნუას ქაკათათინ still_open: თირუეფიშ პაკეტი დიო ღილე რე. სხუნუა ხემიოჭირინაფუ იჸი, მუჭო თირუეფიშ პაკეტი დიკილუნ. + subscribe: გიშაჭარუა + unsubscribe: გიშაჭარუაშ გოუქვაფა + hide_comment: ტყობინაფა + unhide_comment: ძირაფა + comment: კომენტირება changesetxml: თირუეფიშ პაკეტიშ XML osmchangexml: osmChange XML paging_nav: @@ -427,6 +460,8 @@ xmf: show: title: '%{user}შ დღარი | %{title}' user_title: '%{user}შ დღარი' + subscribe: გიშაჭარუა + unsubscribe: გიშაჭარუაშ გოუქვაფა leave_a_comment: კომენტარიშ დოტება login_to_leave_a_comment_html: '%{login_link}, კომენტარიშ დატებელო' login: მიშულა @@ -458,14 +493,28 @@ xmf: title: OpenStreetMap დღარიშ დინნაჭარეფი გეჸვენჯი ნინაშა %{language_name} all: title: OpenStreetMap დღარიშ დინნაჭარეფი + doorkeeper: + flash: + applications: + create: + notice: აპლიკაცია რეგისტრირებული რე. + scopes: + profile: თქვანი ანგარიშიშ ინფორმაციაშ ძირაფა errors: contact: contact: კონტაქტი + bad_request: + title: ჩილათერი მოთხირი + forbidden: + title: ჭირინაფა გოხურგელი internal_server_error: title: აპლიკაციაშ ჩილათა not_found: title: ფაილქ ვეგორჷ geocoder: + search: + title: + latlon: დინოხოლენი search_osm_nominatim: prefix: aerialway: @@ -484,6 +533,7 @@ xmf: terminal: აეროპორტიშ ტერმინალი windsock: ბორიამაძირაფალი amenity: + animal_shelter: ჩხოლარეფიშ ხვაშია arts_centre: ხელუანაფაშ ცენტრი atm: ბანკომატი bank: ბანკი @@ -492,6 +542,7 @@ xmf: bench: დახუნალი bicycle_parking: ველოსიპედეფიშ დგჷმილი bicycle_rental: ველოსპიედეფიშ გაქირაფა + bicycle_repair_station: ველოსიპეტეფიშ აკანწყუალი დგჷმილი biergarten: ლუდიშ ბაღი blood_bank: ზისხირიშ ბანკი boat_rental: ნიშეფიშ გაქირება @@ -531,7 +582,10 @@ xmf: kindergarten: საბაღანო ბაღი language_school: ნინაშ სკოლა library: ბიბლიოთეკა + loading_dock: ოხარგუე დოკი + love_hotel: ჸოროფაშ სასუმარო marketplace: ბაზარი + mobile_money_agent: მობილური ფარაშ აგენტი monastery: მონასტერი money_transfer: ფარაშ ჯღონუა motorcycle_parking: მოტოციკლეტიშ პარკირაფა @@ -624,7 +678,9 @@ xmf: ruins: აკოცჷმილი დგჷმილი school: სკოლა service: ონინალე დგჷმილი + stable: ცხენსაბეკი static_caravan: ქერვანი + sty: ორეჯე temple: ოხიდა terrace: აკიბი train_station: მახინწალიშ დგჷმილი @@ -632,6 +688,7 @@ xmf: warehouse: ოწკარუე "yes": ნოდგჷმი club: + scout: სკაუტეფიშ ბაზა sport: სპორტული კლუბი "yes": კლუბი craft: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index e9f454f7e..2c67e5237 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -3158,6 +3158,8 @@ zh-CN: ninth: 第9 tenth: 第10 time: 时间 + download: 以GeoJSON格式下载路线 + filename: 路线 query: node: 节点 way: 路径 diff --git a/config/routes.rb b/config/routes.rb index 3029a418f..3f4a12bd7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,22 +18,24 @@ 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 + resources :changeset_comments, :id => /\d+/, :only => :index do + resource :visibility, :module => :changeset_comments, :only => [:create, :destroy] + end + post "changeset/comment/:changeset_comment_id/unhide" => "changeset_comments/visibilities#create", :changeset_comment_id => /\d+/, :as => nil + post "changeset/comment/:changeset_comment_id/hide" => "changeset_comments/visibilities#destroy", :changeset_comment_id => /\d+/, :as => nil resources :nodes, :only => [:index, :create] resources :nodes, :path => "node", :id => /\d+/, :only => [:show, :update, :destroy] do diff --git a/lib/osm.rb b/lib/osm.rb index 6710ee88e..b0c314cbc 100644 --- a/lib/osm.rb +++ b/lib/osm.rb @@ -506,10 +506,10 @@ module OSM end # Parse a float, raising a specified exception on failure - def self.parse_float(str, klass, *args) + def self.parse_float(str, klass, *) Float(str) rescue StandardError - raise klass.new(*args) + raise klass.new(*) end # Construct a random token of a given length diff --git a/test/abilities/api_capability_test.rb b/test/abilities/api_capability_test.rb index 58c8f7fe7..0945b6290 100644 --- a/test/abilities/api_capability_test.rb +++ b/test/abilities/api_capability_test.rb @@ -8,9 +8,9 @@ class ChangesetCommentApiCapabilityTest < ActiveSupport::TestCase scopes = Set.new ability = ApiAbility.new user, scopes - [:create, :destroy, :restore].each do |action| - assert ability.cannot? action, ChangesetComment - end + assert ability.cannot? :create, ChangesetComment + assert ability.cannot? :create, :changeset_comment_visibility + assert ability.cannot? :destroy, :changeset_comment_visibility end test "as a normal user with write_changeset_comments scope" do @@ -18,13 +18,9 @@ class ChangesetCommentApiCapabilityTest < ActiveSupport::TestCase scopes = Set.new %w[write_changeset_comments] ability = ApiAbility.new user, scopes - [:destroy, :restore].each do |action| - assert ability.cannot? action, ChangesetComment - end - - [:create].each do |action| - assert ability.can? action, ChangesetComment - end + assert ability.can? :create, ChangesetComment + assert ability.cannot? :create, :changeset_comment_visibility + assert ability.cannot? :destroy, :changeset_comment_visibility end test "as a moderator without scopes" do @@ -32,9 +28,9 @@ class ChangesetCommentApiCapabilityTest < ActiveSupport::TestCase scopes = Set.new ability = ApiAbility.new user, scopes - [:create, :destroy, :restore].each do |action| - assert ability.cannot? action, ChangesetComment - end + assert ability.cannot? :create, ChangesetComment + assert ability.cannot? :create, :changeset_comment_visibility + assert ability.cannot? :destroy, :changeset_comment_visibility end test "as a moderator with write_changeset_comments scope" do @@ -42,9 +38,9 @@ class ChangesetCommentApiCapabilityTest < ActiveSupport::TestCase scopes = Set.new %w[write_changeset_comments] ability = ApiAbility.new user, scopes - [:create, :destroy, :restore].each do |action| - assert ability.can? action, ChangesetComment - end + assert ability.can? :create, ChangesetComment + assert ability.can? :create, :changeset_comment_visibility + assert ability.can? :destroy, :changeset_comment_visibility end end diff --git a/test/controllers/api/changeset_comments/visibilities_controller_test.rb b/test/controllers/api/changeset_comments/visibilities_controller_test.rb new file mode 100644 index 000000000..1e8b562de --- /dev/null +++ b/test/controllers/api/changeset_comments/visibilities_controller_test.rb @@ -0,0 +1,253 @@ +require "test_helper" + +module Api + module ChangesetComments + class VisibilitiesControllerTest < ActionDispatch::IntegrationTest + ## + # test all routes which lead to this controller + def test_routes + assert_routing( + { :path => "/api/0.6/changeset_comments/1/visibility", :method => :post }, + { :controller => "api/changeset_comments/visibilities", :action => "create", :changeset_comment_id => "1" } + ) + assert_routing( + { :path => "/api/0.6/changeset_comments/1/visibility.json", :method => :post }, + { :controller => "api/changeset_comments/visibilities", :action => "create", :changeset_comment_id => "1", :format => "json" } + ) + assert_routing( + { :path => "/api/0.6/changeset_comments/1/visibility", :method => :delete }, + { :controller => "api/changeset_comments/visibilities", :action => "destroy", :changeset_comment_id => "1" } + ) + assert_routing( + { :path => "/api/0.6/changeset_comments/1/visibility.json", :method => :delete }, + { :controller => "api/changeset_comments/visibilities", :action => "destroy", :changeset_comment_id => "1", :format => "json" } + ) + + assert_recognizes( + { :controller => "api/changeset_comments/visibilities", :action => "create", :changeset_comment_id => "1" }, + { :path => "/api/0.6/changeset/comment/1/unhide", :method => :post } + ) + assert_recognizes( + { :controller => "api/changeset_comments/visibilities", :action => "create", :changeset_comment_id => "1", :format => "json" }, + { :path => "/api/0.6/changeset/comment/1/unhide.json", :method => :post } + ) + assert_recognizes( + { :controller => "api/changeset_comments/visibilities", :action => "destroy", :changeset_comment_id => "1" }, + { :path => "/api/0.6/changeset/comment/1/hide", :method => :post } + ) + assert_recognizes( + { :controller => "api/changeset_comments/visibilities", :action => "destroy", :changeset_comment_id => "1", :format => "json" }, + { :path => "/api/0.6/changeset/comment/1/hide.json", :method => :post } + ) + end + + def test_create_by_unauthorized + comment = create(:changeset_comment, :visible => false) + + post api_changeset_comment_visibility_path(comment) + + assert_response :unauthorized + assert_not comment.reload.visible + end + + def test_create_by_normal_user + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header + + post api_changeset_comment_visibility_path(comment), :headers => auth_header + + assert_response :forbidden + assert_not comment.reload.visible + end + + def test_create_on_missing_comment + auth_header = bearer_authorization_header create(:moderator_user) + + post api_changeset_comment_visibility_path(999111), :headers => auth_header + + assert_response :not_found + end + + def test_create_without_required_scope + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[read_prefs] + + post api_changeset_comment_visibility_path(comment), :headers => auth_header + + assert_response :forbidden + assert_not comment.reload.visible + end + + def test_create_with_write_changeset_comments_scope + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] + + post api_changeset_comment_visibility_path(comment), :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => true) + end + + def test_create_with_write_changeset_comments_scope_json + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] + + post api_changeset_comment_visibility_path(comment, :format => "json"), :headers => auth_header + + check_successful_response_json(comment, :comment_visible => true) + end + + def test_create_with_write_api_scope + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post api_changeset_comment_visibility_path(comment), :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => true) + end + + def test_create_with_write_api_scope_json + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post api_changeset_comment_visibility_path(comment, :format => "json"), :headers => auth_header + + check_successful_response_json(comment, :comment_visible => true) + end + + def test_create_at_legacy_route + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post "/api/0.6/changeset/comment/#{comment.id}/unhide", :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => true) + end + + def test_create_at_legacy_route_json + comment = create(:changeset_comment, :visible => false) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post "/api/0.6/changeset/comment/#{comment.id}/unhide.json", :headers => auth_header + + check_successful_response_json(comment, :comment_visible => true) + end + + def test_destroy_by_unauthorized + comment = create(:changeset_comment) + + delete api_changeset_comment_visibility_path(comment) + + assert_response :unauthorized + assert comment.reload.visible + end + + def test_destroy_by_normal_user + comment = create(:changeset_comment) + auth_header = bearer_authorization_header + + delete api_changeset_comment_visibility_path(comment), :headers => auth_header + + assert_response :forbidden + assert comment.reload.visible + end + + def test_destroy_on_missing_comment + auth_header = bearer_authorization_header create(:moderator_user) + + delete api_changeset_comment_visibility_path(999111), :headers => auth_header + + assert_response :not_found + end + + def test_destroy_without_required_scope + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[read_prefs] + + delete api_changeset_comment_visibility_path(comment), :headers => auth_header + + assert_response :forbidden + assert comment.reload.visible + end + + def test_destroy_with_write_changeset_comments_scope + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] + + delete api_changeset_comment_visibility_path(comment), :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => false) + end + + def test_destroy_with_write_changeset_comments_scope_json + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] + + delete api_changeset_comment_visibility_path(comment, :format => "json"), :headers => auth_header + + check_successful_response_json(comment, :comment_visible => false) + end + + def test_destroy_with_write_api_scope + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + delete api_changeset_comment_visibility_path(comment), :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => false) + end + + def test_destroy_with_write_api_scope_json + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + delete api_changeset_comment_visibility_path(comment, :format => "json"), :headers => auth_header + + check_successful_response_json(comment, :comment_visible => false) + end + + def test_destroy_at_legacy_route + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post "/api/0.6/changeset/comment/#{comment.id}/hide", :headers => auth_header + + check_successful_response_xml(comment, :comment_visible => false) + end + + def test_destroy_at_legacy_route_json + comment = create(:changeset_comment) + auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] + + post "/api/0.6/changeset/comment/#{comment.id}/hide.json", :headers => auth_header + + check_successful_response_json(comment, :comment_visible => false) + end + + private + + def check_successful_response_xml(comment, comment_visible:) + assert_response :success + assert_equal "application/xml", response.media_type + assert_dom "osm", 1 do + assert_dom "> changeset", 1 do + assert_dom "> @id", comment.changeset_id.to_s + assert_dom "> @comments_count", comment_visible ? "1" : "0" + end + end + + assert_equal comment_visible, comment.reload.visible + end + + def check_successful_response_json(comment, comment_visible:) + assert_response :success + assert_equal "application/json", response.media_type + js = ActiveSupport::JSON.decode(@response.body) + assert_not_nil js["changeset"] + assert_equal comment.changeset_id, js["changeset"]["id"] + assert_equal comment_visible ? 1 : 0, js["changeset"]["comments_count"] + + assert_equal comment_visible, comment.reload.visible + end + end + end +end diff --git a/test/controllers/api/changeset_comments_controller_test.rb b/test/controllers/api/changeset_comments_controller_test.rb index 72463ed67..b16ea4502 100644 --- a/test/controllers/api/changeset_comments_controller_test.rb +++ b/test/controllers/api/changeset_comments_controller_test.rb @@ -15,27 +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" } - ) - assert_routing( - { :path => "/api/0.6/changeset/comment/1/hide", :method => :post }, - { :controller => "api/changeset_comments", :action => "destroy", :id => "1" } - ) - assert_routing( - { :path => "/api/0.6/changeset/comment/1/hide.json", :method => :post }, - { :controller => "api/changeset_comments", :action => "destroy", :id => "1", :format => "json" } - ) - assert_routing( - { :path => "/api/0.6/changeset/comment/1/unhide", :method => :post }, - { :controller => "api/changeset_comments", :action => "restore", :id => "1" } - ) - assert_routing( - { :path => "/api/0.6/changeset/comment/1/unhide.json", :method => :post }, - { :controller => "api/changeset_comments", :action => "restore", :id => "1", :format => "json" } + { :controller => "api/changeset_comments", :action => "create", :changeset_id => "1", :format => "json" } ) end @@ -81,35 +65,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 +104,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 +115,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 +126,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 +143,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 +161,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 +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 @@ -209,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 @@ -226,7 +210,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 +234,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 +261,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 +283,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 +305,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,131 +326,17 @@ 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 - def test_hide_by_unauthorized - comment = create(:changeset_comment) - - post changeset_comment_hide_path(comment) - - assert_response :unauthorized - assert comment.reload.visible - end - - def test_hide_by_normal_user - comment = create(:changeset_comment) - auth_header = bearer_authorization_header - - post changeset_comment_hide_path(comment), :headers => auth_header - - assert_response :forbidden - assert comment.reload.visible - end - - def test_hide_missing_comment - auth_header = bearer_authorization_header create(:moderator_user) - - post changeset_comment_hide_path(999111), :headers => auth_header - - assert_response :not_found - end - - def test_hide_without_required_scope - comment = create(:changeset_comment) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[read_prefs] - - post changeset_comment_hide_path(comment), :headers => auth_header - - assert_response :forbidden - assert comment.reload.visible - end - - def test_hide_with_write_changeset_comments_scope - comment = create(:changeset_comment) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] - - post changeset_comment_hide_path(comment), :headers => auth_header - - assert_response :success - assert_not comment.reload.visible - end - - def test_hide_with_write_api_scope - comment = create(:changeset_comment) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] - - post changeset_comment_hide_path(comment), :headers => auth_header - - assert_response :success - assert_not comment.reload.visible - end - - def test_unhide_by_unauthorized - comment = create(:changeset_comment, :visible => false) - - post changeset_comment_unhide_path(comment) - - assert_response :unauthorized - assert_not comment.reload.visible - end - - def test_unhide_by_normal_user - comment = create(:changeset_comment, :visible => false) - auth_header = bearer_authorization_header - - post changeset_comment_unhide_path(comment), :headers => auth_header - - assert_response :forbidden - assert_not comment.reload.visible - end - - def test_unhide_missing_comment - auth_header = bearer_authorization_header create(:moderator_user) - - post changeset_comment_unhide_path(999111), :headers => auth_header - - assert_response :not_found - end - - def test_unhide_without_required_scope - comment = create(:changeset_comment, :visible => false) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[read_prefs] - - post changeset_comment_unhide_path(comment), :headers => auth_header - - assert_response :forbidden - assert_not comment.reload.visible - end - - def test_unhide_with_write_changeset_comments_scope - comment = create(:changeset_comment, :visible => false) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_changeset_comments] - - post changeset_comment_unhide_path(comment), :headers => auth_header - - assert_response :success - assert comment.reload.visible - end - - def test_unhide_with_write_api_scope - comment = create(:changeset_comment, :visible => false) - auth_header = bearer_authorization_header create(:moderator_user), :scopes => %w[write_api] - - post changeset_comment_unhide_path(comment), :headers => auth_header - - assert_response :success - assert comment.reload.visible - end - private ## diff --git a/test/controllers/api/changesets/downloads_controller_test.rb b/test/controllers/api/changesets/downloads_controller_test.rb new file mode 100644 index 000000000..9eda6ec1d --- /dev/null +++ b/test/controllers/api/changesets/downloads_controller_test.rb @@ -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 diff --git a/test/controllers/api/changesets_controller_test.rb b/test/controllers/api/changesets_controller_test.rb index e73459a36..87deb3bdf 100644 --- a/test/controllers/api/changesets_controller_test.rb +++ b/test/controllers/api/changesets_controller_test.rb @@ -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 diff --git a/test/controllers/api/relations_controller_test.rb b/test/controllers/api/relations_controller_test.rb index f585c5c2c..a4c8522e8 100644 --- a/test/controllers/api/relations_controller_test.rb +++ b/test/controllers/api/relations_controller_test.rb @@ -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}" diff --git a/test/controllers/notes_controller_test.rb b/test/controllers/notes_controller_test.rb index a70bb32cd..0185c6741 100644 --- a/test/controllers/notes_controller_test.rb +++ b/test/controllers/notes_controller_test.rb @@ -164,7 +164,7 @@ class NotesControllerTest < ActionDispatch::IntegrationTest def test_read_note_suspended_opener_and_comment note = create(:note) create(:note_comment, :note => note, :author => create(:user, :suspended)) - create(:note_comment, :note => note) + create(:note_comment, :note => note, :event => "commented") sidebar_browse_check :note_path, note.id, "notes/show" assert_select "div.note-comments ul li", :count => 1 diff --git a/test/controllers/users/lists_controller_test.rb b/test/controllers/users/lists_controller_test.rb index b683107d9..724c43222 100644 --- a/test/controllers/users/lists_controller_test.rb +++ b/test/controllers/users/lists_controller_test.rb @@ -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 diff --git a/yarn.lock b/yarn.lock index 71a706e45..bc2be6e82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,33 +19,26 @@ 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" @@ -57,22 +50,22 @@ 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": @@ -98,15 +91,15 @@ 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" - resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.0.1.tgz#c55e59ad2f00914f9eb103ba9e7be00aff7715dd" - integrity sha512-2EGKM6WHnZSidWKCu6ePJCqdpgWiEU1Bt26ktWEfTpCmRP+2vRQ6ViK8X6DLwu4+F0zPLy/Txe2HhI3qJFUvqA== + version "4.1.0" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.1.0.tgz#cb3fcc6bef022f1af8245a6cda404d290358c260" + integrity sha512-YOe+dChNoR26JVVt+7BjyebsPIQF05OLNmHCXivq8lLZ4ZeVs4+wXaW+pREVboDiAaSRznauAdAU8f+iQouw6Q== dependencies: eslint-visitor-keys "^4.2.0" espree "^10.3.0" @@ -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"