]> git.openstreetmap.org Git - rails.git/commitdiff
Merge remote-tracking branch 'upstream/pull/4329'
authorTom Hughes <tom@compton.nu>
Tue, 28 Nov 2023 22:21:50 +0000 (22:21 +0000)
committerTom Hughes <tom@compton.nu>
Tue, 28 Nov 2023 22:21:50 +0000 (22:21 +0000)
55 files changed:
.github/workflows/lint.yml
.github/workflows/tests.yml
.rubocop_todo.yml
Gemfile
Gemfile.lock
app/abilities/api_ability.rb
app/assets/images/key/mapnik/rail12.png [moved from app/assets/images/key/mapnik/rail13.png with 100% similarity]
app/assets/javascripts/application.js
app/assets/javascripts/leaflet.key.js
app/assets/javascripts/leaflet.share.js
app/assets/javascripts/osm.js.erb
app/assets/stylesheets/common.scss
app/assets/stylesheets/print-rtl.rtlcss.scss [moved from app/assets/stylesheets/print-rtl.r2.scss with 100% similarity]
app/assets/stylesheets/screen-rtl.rtlcss.scss [moved from app/assets/stylesheets/screen-rtl.r2.scss with 100% similarity]
app/controllers/accounts_controller.rb
app/controllers/api/changesets_controller.rb
app/controllers/api/notes_controller.rb
app/controllers/changesets_controller.rb
app/models/changeset.rb
app/models/user.rb
app/views/account/deletions/show.html.erb
app/views/api/changesets/changeset.xml.builder
app/views/api/changesets/changesets.xml.builder
app/views/layouts/_header.html.erb
config/environments/test.rb
config/initializers/config.rb
config/initializers/r2.rb [deleted file]
config/initializers/rtlcss.rb [new file with mode: 0644]
config/key.yml
config/locales/ar.yml
config/locales/bn.yml
config/locales/br.yml
config/locales/en.yml
config/locales/fi.yml
config/locales/fr.yml
config/locales/gl.yml
config/locales/he.yml
config/locales/hi.yml
config/locales/ia.yml
config/locales/kn.yml
config/locales/mk.yml
config/locales/nl.yml
config/locales/sc.yml
config/locales/sco.yml
config/locales/zh-TW.yml
config/settings.yml
db/migrate/20231117170422_add_closed_at_index_to_changesets.rb [new file with mode: 0644]
db/structure.sql
test/abilities/api_abilities_test.rb
test/controllers/accounts_controller_test.rb
test/controllers/oauth2_authorizations_controller_test.rb
test/models/user_test.rb
test/system/account_deletion_test.rb
test/test_helper.rb
yarn.lock

index 2050aaf3f264f416a41f58fa2cfeb4167eb8a7dc..0608b699bdfdcc56bb6f3f10087762b3546e3140 100644 (file)
@@ -19,6 +19,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ env.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Run rubocop
       run: bundle exec rubocop --format fuubar
@@ -32,6 +33,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ env.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Run erblint
       run: bundle exec erblint .
@@ -45,6 +47,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ env.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Cache node modules
       uses: actions/cache@v3
@@ -69,6 +72,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ env.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Run brakeman
       run: bundle exec brakeman -q
@@ -84,6 +88,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ env.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Setup database
       run: |
index 3ee6129e113799a8818f455694e55266df9c6792..2588a737f2e69f2894f15f54ccb3716466ef93ed 100644 (file)
@@ -23,6 +23,7 @@ jobs:
       uses: ruby/setup-ruby@v1
       with:
         ruby-version: ${{ matrix.ruby }}
+        rubygems: 3.4.10
         bundler-cache: true
     - name: Cache node modules
       uses: actions/cache@v3
index e3407c6dc0111d811f1b34377429a46d63a2d14a..bd2f92309886c83b83e4dfdaecd5cc8153f23cc7 100644 (file)
@@ -61,7 +61,7 @@ Metrics/BlockNesting:
 # Offense count: 26
 # Configuration parameters: CountComments, CountAsOne.
 Metrics/ClassLength:
-  Max: 286
+  Max: 297
 
 # Offense count: 59
 # Configuration parameters: AllowedMethods, AllowedPatterns.
diff --git a/Gemfile b/Gemfile
index f9f12d64e9b31de332cc38b5e04aea420249eaf5..98b03518877a8ef6a8a157e66af9f3d9e9049cb0 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -26,8 +26,8 @@ gem "jbuilder", "~> 2.7"
 # Reduces boot times through caching; required in config/boot.rb
 gem "bootsnap", ">= 1.4.2", :require => false
 
-# Use R2 for RTL conversion
-gem "r2", "~> 0.2.7"
+# Use rtlcss for RTL conversion
+gem "rtlcss"
 
 # Use autoprefixer to generate CSS prefixes
 gem "autoprefixer-rails"
index c313665c43485cc8c98aec8360aecd94565490dc..ec0ec403f839fbb0e6361f9309a8112ae922b250 100644 (file)
@@ -65,7 +65,7 @@ GEM
       activemodel (= 7.1.2)
       activesupport (= 7.1.2)
       timeout (>= 0.4.0)
-    activerecord-import (1.5.0)
+    activerecord-import (1.5.1)
       activerecord (>= 4.2)
     activestorage (7.1.2)
       actionpack (= 7.1.2)
@@ -92,23 +92,23 @@ GEM
       ffi (~> 1.15)
       ffi-compiler (~> 1.0)
     ast (2.4.2)
-    autoprefixer-rails (10.4.15.0)
+    autoprefixer-rails (10.4.16.0)
       execjs (~> 2)
-    aws-eventstream (1.2.0)
-    aws-partitions (1.849.0)
-    aws-sdk-core (3.186.0)
+    aws-eventstream (1.3.0)
+    aws-partitions (1.859.0)
+    aws-sdk-core (3.188.0)
       aws-eventstream (~> 1, >= 1.0.2)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.5)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.72.0)
-      aws-sdk-core (~> 3, >= 3.184.0)
+    aws-sdk-kms (1.73.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.136.0)
-      aws-sdk-core (~> 3, >= 3.181.0)
+    aws-sdk-s3 (1.140.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.6)
-    aws-sigv4 (1.6.1)
+    aws-sigv4 (1.7.0)
       aws-eventstream (~> 1, >= 1.0.2)
     base64 (0.2.0)
     better_errors (2.10.1)
@@ -177,7 +177,7 @@ GEM
       activerecord (>= 3.0, < 8.0)
       delayed_job (>= 3.0, < 5)
     docile (1.4.0)
-    doorkeeper (5.6.6)
+    doorkeeper (5.6.7)
       railties (>= 5)
     doorkeeper-i18n (5.2.7)
       doorkeeper (>= 5.2)
@@ -228,12 +228,12 @@ GEM
     erubi (1.12.0)
     execjs (2.9.1)
     exifr (1.4.0)
-    factory_bot (6.2.1)
+    factory_bot (6.4.2)
       activesupport (>= 5.0.0)
-    factory_bot_rails (6.2.0)
-      factory_bot (~> 6.2.0)
+    factory_bot_rails (6.4.2)
+      factory_bot (~> 6.4)
       railties (>= 5.0.0)
-    faraday (2.7.11)
+    faraday (2.7.12)
       base64
       faraday-net_http (>= 2.0, < 3.1)
       ruby2_keywords (>= 0.0.4)
@@ -251,7 +251,7 @@ GEM
       ffi (>= 1.0.0)
     globalid (1.2.1)
       activesupport (>= 6.1)
-    google-protobuf (3.25.0)
+    google-protobuf (3.25.1)
     hashdiff (1.0.1)
     hashie (5.0.0)
     highline (2.1.0)
@@ -288,7 +288,7 @@ GEM
     image_size (3.3.0)
     in_threads (1.6.0)
     io-console (0.6.0)
-    irb (1.9.0)
+    irb (1.9.1)
       rdoc
       reline (>= 0.3.8)
     jbuilder (2.11.5)
@@ -305,6 +305,7 @@ GEM
     kramdown (2.4.0)
       rexml
     language_server-protocol (3.17.0.3)
+    libv8-node (18.16.0.0)
     libxml-ruby (4.1.2)
     listen (3.8.0)
       rb-fsevent (~> 0.10, >= 0.10.3)
@@ -326,12 +327,14 @@ GEM
     mini_magick (4.12.0)
     mini_mime (1.1.5)
     mini_portile2 (2.8.5)
+    mini_racer (0.8.0)
+      libv8-node (~> 18.16.0.0)
     minitest (5.20.0)
     msgpack (1.7.2)
     multi_json (1.15.0)
     multi_xml (0.6.0)
     mutex_m (0.2.0)
-    net-imap (0.4.5)
+    net-imap (0.4.6)
       date
       net-protocol
     net-pop (0.1.2)
@@ -340,8 +343,8 @@ GEM
       timeout
     net-smtp (0.4.0)
       net-protocol
-    nio4r (2.5.9)
-    nokogiri (1.15.4)
+    nio4r (2.6.1)
+    nokogiri (1.15.5)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     oauth (0.4.7)
@@ -399,11 +402,10 @@ GEM
     progress (3.6.0)
     psych (5.1.1.1)
       stringio
-    public_suffix (5.0.3)
+    public_suffix (5.0.4)
     puma (5.6.7)
       nio4r (~> 2.0)
     quad_tile (1.0.1)
-    r2 (0.2.8)
     racc (1.7.3)
     rack (2.2.8)
     rack-cors (2.0.1)
@@ -465,7 +467,7 @@ GEM
     rdoc (6.6.0)
       psych (>= 4.0.0)
     regexp_parser (2.8.2)
-    reline (0.4.0)
+    reline (0.4.1)
       io-console (~> 0.5)
     request_store (1.5.1)
       rack (>= 1.4)
@@ -473,6 +475,8 @@ GEM
     rinku (2.0.6)
     rotp (6.3.0)
     rouge (4.2.0)
+    rtlcss (0.2.1)
+      mini_racer (>= 0.6.3)
     rubocop (1.57.2)
       json (~> 2.3)
       language_server-protocol (>= 3.17.0)
@@ -495,10 +499,11 @@ GEM
     rubocop-performance (1.19.1)
       rubocop (>= 1.7.0, < 2.0)
       rubocop-ast (>= 0.4.0)
-    rubocop-rails (2.22.1)
+    rubocop-rails (2.22.2)
       activesupport (>= 4.2.0)
       rack (>= 1.1)
       rubocop (>= 1.33.0, < 2.0)
+      rubocop-ast (>= 1.30.0, < 2.0)
     rubocop-rake (0.6.0)
       rubocop (~> 1.0)
     ruby-openid (2.9.2)
@@ -539,12 +544,12 @@ GEM
       actionpack (>= 5.2)
       activesupport (>= 5.2)
       sprockets (>= 3.0.0)
-    stringio (3.0.9)
+    stringio (3.1.0)
     strong_migrations (1.6.4)
       activerecord (>= 5.2)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
-    terser (1.1.19)
+    terser (1.1.20)
       execjs (>= 0.3.0, < 3)
     thor (1.3.0)
     tilt (2.3.0)
@@ -638,7 +643,6 @@ DEPENDENCIES
   pg
   puma (~> 5.6)
   quad_tile (~> 1.0.1)
-  r2 (~> 0.2.7)
   rack-cors
   rack-uri_sanitizer
   rails (~> 7.1.0)
@@ -646,6 +650,7 @@ DEPENDENCIES
   rails-i18n (~> 7.0.0)
   rinku (>= 2.0.6)
   rotp
+  rtlcss
   rubocop
   rubocop-capybara
   rubocop-factory_bot
index fe39f5eb5aa2475a4d1c56fa9456e9a8842d117a..4876380d0dd272e708f0180be8b3df13d3d9c88a 100644 (file)
@@ -12,7 +12,7 @@ class ApiAbility
 
     if Settings.status != "database_offline"
       can [:show, :download, :query], Changeset
-      can [:index, :create, :comment, :feed, :show, :search], Note
+      can [:index, :create, :feed, :show, :search], Note
       can :index, Tracepoint
       can [:index, :show], User
       can [:index, :show], Node
@@ -31,7 +31,7 @@ class ApiAbility
       if Settings.status != "database_offline"
         can [:index, :new, :create, :show, :edit, :update, :destroy], ClientApplication
         can [:new, :create, :reply, :show, :inbox, :outbox, :mark, :destroy], Message
-        can [:close, :reopen], Note
+        can [:comment, :close, :reopen], Note
         can [:new, :create], Report
         can [:create, :show, :update, :destroy, :data], Trace
         can [:details, :gpx_files], User
index af67244bcb706604ed139f4758bb3bef504970b3..0bfff869ebcc87186c1aec12c4a0ff75949a923f 100644 (file)
@@ -103,6 +103,8 @@ $(document).ready(function () {
 
     $("body").removeClass("compact-nav");
 
+    $("header").removeClass("text-nowrap");
+
     updateHeader();
 
     $(window).resize(updateHeader);
index 6a3400d348831ab48ff53b5f1a2f9e991307f52b..bcd5839cdad8891e183e2fcec8bf7c19b14e4191 100644 (file)
@@ -24,7 +24,7 @@ L.OSM.key = function (options) {
     }
 
     function updateButton() {
-      var disabled = ["mapnik", "cyclemap"].indexOf(map.getMapBaseLayerId()) === -1;
+      var disabled = OSM.LAYERS_WITH_MAP_KEY.indexOf(map.getMapBaseLayerId()) === -1;
       button
         .toggleClass("disabled", disabled)
         .attr("data-bs-original-title",
index c096a92fcf725b4d2ce3e2d144416cfcdfe726fc..eb351fa026ac6aa3f85f66461155e2ade36e4dc1 100644 (file)
@@ -46,10 +46,13 @@ L.OSM.share = function (options) {
         .text(I18n.t("javascripts.share.short_link")))
       .append($("<a class='btn btn-primary'>")
         .attr("for", "embed_html")
+        .attr("id", "embed_link")
+        .attr("data-bs-title", I18n.t("javascripts.site.embed_html_disabled"))
         .attr("href", "#")
         .text(I18n.t("javascripts.share.embed")))
       .on("click", "a", function (e) {
         e.preventDefault();
+        if (!$(this).hasClass("btn-primary")) return;
         var id = "#" + $(this).attr("for");
         $(this).siblings("a")
           .removeClass("active");
@@ -309,6 +312,7 @@ L.OSM.share = function (options) {
     }
 
     function update() {
+      var canEmbed = map.getMapBaseLayerId() !== "tracestracktopo";
       var bounds = map.getBounds();
 
       $("#link_marker")
@@ -334,6 +338,14 @@ L.OSM.share = function (options) {
         params.marker = latLng.lat + "," + latLng.lng;
       }
 
+      $("#embed_link")
+        .toggleClass("btn-primary", canEmbed)
+        .toggleClass("btn-secondary", !canEmbed)
+        .tooltip(canEmbed ? "disable" : "enable");
+      if (!canEmbed && $("#embed_link").hasClass("active")) {
+        $("#long_link").click();
+      }
+
       $("#embed_html").val(
         "<iframe width=\"425\" height=\"350\" src=\"" +
           escapeHTML(OSM.SERVER_PROTOCOL + "://" + OSM.SERVER_URL + "/export/embed.html?" + $.param(params)) +
index 0a0f5c67a7c5a9df678e3cb1e7168f46f90434ee..2e33438dbdef6bc9c821e8c217ed41415d05eb08 100644 (file)
@@ -1,5 +1,6 @@
 //= depend_on settings.yml
 //= depend_on settings.local.yml
+//= depend_on key.yml
 //= require qs/dist/qs
 
 OSM = {
@@ -29,6 +30,8 @@ OSM = {
   TRACESTRACK_KEY:         <%= Settings.tracestrack_key.to_json %>,
 <% end %>
 
+  LAYERS_WITH_MAP_KEY:     <%= YAML.load_file(Rails.root.join("config/key.yml")).keys.to_json %>,
+
   MARKER_GREEN:            <%= image_path("marker-green.png").to_json %>,
   MARKER_RED:              <%= image_path("marker-red.png").to_json %>,
 
index 1f5d0398e97b2b11433355821a69f11e4ee6c215..c3a31d834a51a841d7220b6334c33788e2c9d21b 100644 (file)
@@ -2,34 +2,6 @@
 @import "bootstrap";
 @import "rails_bootstrap_forms";
 
-/* Bootstrap + r2 fixes */
-
-:root[dir=rtl] {
-  .bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow {
-    /* no-r2 */
-    right: unset !important;
-    left: calc(-1 * var(--bs-tooltip-arrow-height)) !important;
-
-    &::before {
-      /* no-r2 */
-      left: unset !important;
-      right: -1px !important;
-    }
-  }
-
-  .bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow {
-    /* no-r2 */
-    left: unset !important;
-    right: calc(-1 * var(--bs-tooltip-arrow-height)) !important;
-
-    &::before {
-      /* no-r2 */
-      right: unset !important;
-      left: -1px !important;
-    }
-  }
-}
-
 /* Styles common to large and small screens */
 
 /* Default rules for the body of every page */
@@ -71,23 +43,23 @@ time[title] {
   overflow: hidden;
 }
 
-.icon.search      { /* no-r2 */ background-position: 0 0; }
-.icon.donate      { /* no-r2 */ background-position: -20px 0; }
-.icon.zoomin      { /* no-r2 */ background-position: -40px 0; }
-.icon.zoomout     { /* no-r2 */ background-position: -60px 0; }
-.icon.geolocate   { /* no-r2 */ background-position: -80px 0; }
-.active .icon.geolocate   { /* no-r2 */ background-position: -80px -20px; }
-.icon.layers      { /* no-r2 */ background-position: -100px 0; }
-.icon.key         { /* no-r2 */ background-position: -120px 0; }
-.icon.share       { /* no-r2 */ background-position: -140px 0; }
-.icon.clipboard   { /* no-r2 */ background-position: -160px 0; }
-.icon.link        { /* no-r2 */ background-position: -180px 0; }
-.icon.close       { /* no-r2 */ background-position: -200px 0; }
-.icon.close:hover { /* no-r2 */ background-position: -200px -20px; }
-.icon.check       { /* no-r2 */ background-position: -220px 0; }
-.icon.note        { /* no-r2 */ background-position: -240px 0; }
-.icon.note.grey   { /* no-r2 */ background-position: -240px -20px; }
-.icon.query       { /* no-r2 */ background-position: -260px 0; }
+.icon.search      { /*rtl:ignore*/ background-position: 0 0; }
+.icon.donate      { /*rtl:ignore*/ background-position: -20px 0; }
+.icon.zoomin      { /*rtl:ignore*/ background-position: -40px 0; }
+.icon.zoomout     { /*rtl:ignore*/ background-position: -60px 0; }
+.icon.geolocate   { /*rtl:ignore*/ background-position: -80px 0; }
+.active .icon.geolocate   { /*rtl:ignore*/ background-position: -80px -20px; }
+.icon.layers      { /*rtl:ignore*/ background-position: -100px 0; }
+.icon.key         { /*rtl:ignore*/ background-position: -120px 0; }
+.icon.share       { /*rtl:ignore*/ background-position: -140px 0; }
+.icon.clipboard   { /*rtl:ignore*/ background-position: -160px 0; }
+.icon.link        { /*rtl:ignore*/ background-position: -180px 0; }
+.icon.close       { /*rtl:ignore*/ background-position: -200px 0; }
+.icon.close:hover { /*rtl:ignore*/ background-position: -200px -20px; }
+.icon.check       { /*rtl:ignore*/ background-position: -220px 0; }
+.icon.note        { /*rtl:ignore*/ background-position: -240px 0; }
+.icon.note.grey   { /*rtl:ignore*/ background-position: -240px -20px; }
+.icon.query       { /*rtl:ignore*/ background-position: -260px 0; }
 
 /* Utility for de-emphasizing content */
 
@@ -109,7 +81,9 @@ time[title] {
 
 #menu-icon {
   display: none;
-  float: right;
+  position: absolute;
+  top: 0;
+  right: 0;
   background: image-url("menu-icon.png") no-repeat;
   background-size: 30px 30px;
   width: 30px;
@@ -133,10 +107,6 @@ header {
     padding: $lineheight * 0.5;
   }
 
-  h1, nav.primary {
-    float: left;
-  }
-
   img.logo {
     margin-top: -2px;
   }
@@ -150,8 +120,11 @@ header {
   .btn {
     font-size: 14px;
   }
-}
 
+  nav.primary {
+    margin-right: auto;
+  }
+}
 
 nav.primary {
   & > .btn-group .btn-outline-primary {
@@ -186,9 +159,6 @@ nav.primary {
 }
 
 nav.secondary {
-  position: absolute;
-  right: 0;
-
   .nav-link {
     padding: 0.2rem;
     color: $darkgrey;
@@ -230,15 +200,8 @@ body.small-nav {
     display: block;
   }
 
-  nav.primary,
-  nav.secondary {
-    float: none !important;
-    position: relative;
-    display: block;
-    clear: both;
-  }
-
   header {
+    flex-direction: column;
     height: auto;
     min-height: $headerHeight;
     background: #fff;
@@ -259,28 +222,9 @@ body.small-nav {
   }
 
   nav.primary {
+    margin-right: 0;
     padding: 0;
 
-    ul, li {
-      border: none;
-      border-radius: 0;
-      width: 100%;
-    }
-
-    ul {
-      border-top: 1px solid #eee;
-      li {
-        border-bottom: 1px solid #eee;
-        border-right: none;
-        > a {
-          border-radius: 0;
-          width: 100%;
-          text-align: center;
-          font-size: 15px;
-        }
-      }
-    }
-
     .btn-group {
       width: 100%;
       padding: 10px;
@@ -757,6 +701,12 @@ tr.turn:hover {
   }
 }
 
+/* Force LTR/RTL alignment for placeholder text */
+
+.form-control::placeholder {
+  text-align: left;
+}
+
 /* Rules for export sidebar */
 
 .export_form {
@@ -779,11 +729,11 @@ tr.turn:hover {
     #maxlat { margin-top: -1px; }
     #minlon {
       float: left;
-      /* no-r2 */ margin-left: -1px;
+      /*rtl:ignore*/ margin-left: -1px;
     }
     #maxlon {
       float: right;
-      /* no-r2 */ margin-right: -1px;
+      /*rtl:ignore*/ margin-right: -1px;
     }
     #minlat { margin-bottom: -1px; }
   }
@@ -965,10 +915,9 @@ img.user_thumbnail {
 }
 
 img.user_thumbnail_tiny {
-  width: auto;
-  height: auto;
-  max-width: 25px;
-  max-height: 25px;
+  width: 25px;
+  height: 25px;
+  object-fit: contain;
 }
 
 /* General styles for action lists / subnavs */
@@ -1048,7 +997,7 @@ div.secondary-actions {
   }
 
   .sprite.x {
-    /* no-r2 */ background-position: -50px 0;
+    /*rtl:ignore*/ background-position: -50px 0;
   }
 
   .sprite.term {
@@ -1057,27 +1006,27 @@ div.secondary-actions {
   }
 
   .sprite.node {
-    /* no-r2 */ background-position: -100px 0;
+    /*rtl:ignore*/ background-position: -100px 0;
   }
 
   .sprite.way {
-    /* no-r2 */ background-position: -150px 0;
+    /*rtl:ignore*/ background-position: -150px 0;
   }
 
   .sprite.tag {
-    /* no-r2 */ background-position: -200px 0;
+    /*rtl:ignore*/ background-position: -200px 0;
   }
 
   .sprite.editor {
-    /* no-r2 */ background-position: -250px 0;
+    /*rtl:ignore*/ background-position: -250px 0;
   }
 
   .sprite.question {
-    /* no-r2 */ background-position: -300px 0;
+    /*rtl:ignore*/ background-position: -300px 0;
   }
 
   .sprite.rules {
-    /* no-r2 */ background-position: -350px 0;
+    /*rtl:ignore*/ background-position: -350px 0;
   }
 
   .icon.note {
@@ -1128,27 +1077,27 @@ div.secondary-actions {
     background: 40px 40px image-url('about/sprite.png') no-repeat;
 
     &.local {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: 0px 0px;
     }
     &.community {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: 0px -40px;
     }
     &.open {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: 0px -80px;
     }
     &.partners {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: 0px -120px;
     }
     &.infringement {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: 0px -160px;
     }
     &.legal {
-      /* no-r2 */
+      /*rtl:ignore*/
       background-position: -45px -160px;
     }
   }
index 63da1293ff731ecfe85d0430f9c6f0f1819a2008..db972101088b2a958fa0f3ffe25798fec41f1bbf 100644 (file)
@@ -53,12 +53,16 @@ class AccountsController < ApplicationController
   end
 
   def destroy
-    current_user.soft_destroy!
+    if current_user.deletion_allowed?
+      current_user.soft_destroy!
 
-    session.delete(:user)
-    session_expires_automatically
+      session.delete(:user)
+      session_expires_automatically
 
-    flash[:notice] = t ".success"
-    redirect_to root_path
+      flash[:notice] = t ".success"
+      redirect_to root_path
+    else
+      head :bad_request
+    end
   end
 end
index 9bdf0f2bd3b075a5a5eb09e5755bfa76ee224bde..c9c806de6ecc4a7e19d2d345180c87ea3d643493 100644 (file)
@@ -283,7 +283,6 @@ module Api
     ##
     # if a bounding box was specified do some sanity checks.
     # restrict changesets to those enclosed by a bounding box
-    # we need to return both the changesets and the bounding box
     def conditions_bbox(changesets, bbox)
       if bbox
         bbox.check_boundaries
index 95466781f84c8bd97a8fef6c6bea1332d26f6388..8a0a82c40150687063fbf0720b5114c409c73725 100644 (file)
@@ -138,9 +138,6 @@ module Api
     ##
     # Add a comment to an existing note
     def comment
-      # Check the ACLs
-      raise OSM::APIAccessDenied if current_user.nil? && Acl.no_note_comment(request.remote_ip)
-
       # Check the arguments are sane
       raise OSM::APIBadUserInput, "No id was given" unless params[:id]
       raise OSM::APIBadUserInput, "No text was given" if params[:text].blank?
@@ -389,8 +386,14 @@ module Api
     def add_comment(note, text, event, notify: true)
       attributes = { :visible => true, :event => event, :body => text }
 
-      if current_user
-        attributes[:author_id] = current_user.id
+      if doorkeeper_token || current_token
+        author = current_user if scope_enabled?(:write_notes)
+      else
+        author = current_user
+      end
+
+      if author
+        attributes[:author_id] = author.id
       else
         attributes[:author_ip] = request.remote_ip
       end
index fef4d85eb51273596dfe81ccfc0cad88ba81c19f..859242b60fff5106ec2361b724f2972c5d423ab1 100644 (file)
@@ -83,7 +83,6 @@ class ChangesetsController < ApplicationController
   ##
   # if a bounding box was specified do some sanity checks.
   # restrict changesets to those enclosed by a bounding box
-  # we need to return both the changesets and the bounding box
   def conditions_bbox(changesets, bbox)
     if bbox
       bbox.check_boundaries
index ce09438245844be0ff4ba241818973cdf26b5bab..137de18fd6479640c42688df2aceff3f56f1bfbb 100644 (file)
 #
 # Indexes
 #
-#  changesets_bbox_idx                (min_lat,max_lat,min_lon,max_lon) USING gist
-#  changesets_closed_at_idx           (closed_at)
-#  changesets_created_at_idx          (created_at)
-#  changesets_user_id_created_at_idx  (user_id,created_at)
-#  changesets_user_id_id_idx          (user_id,id)
+#  changesets_bbox_idx                        (min_lat,max_lat,min_lon,max_lon) USING gist
+#  changesets_closed_at_idx                   (closed_at)
+#  changesets_created_at_idx                  (created_at)
+#  changesets_user_id_created_at_idx          (user_id,created_at)
+#  changesets_user_id_id_idx                  (user_id,id)
+#  index_changesets_on_user_id_and_closed_at  (user_id,closed_at)
 #
 # Foreign Keys
 #
index 7571dd9dc5c8011f4615ebf970b6f0daa377adc9..1942a25cc237a784394b91f9ba64c844f36e3309 100644 (file)
@@ -419,6 +419,18 @@ class User < ApplicationRecord
     end
   end
 
+  def deletion_allowed_at
+    unless Settings.user_account_deletion_delay.nil?
+      last_changeset = changesets.reorder(:closed_at => :desc).first
+      return last_changeset.closed_at.utc + Settings.user_account_deletion_delay.hours if last_changeset
+    end
+    creation_time.utc
+  end
+
+  def deletion_allowed?
+    deletion_allowed_at <= Time.now.utc
+  end
+
   private
 
   def encrypt_password
index ddc8216772878300b3348b5ff55fd4f6608dbcc0..0ed4d663f03315944f9f7d5b1df1e82a81042f7e 100644 (file)
   <li><%= t ".retain_email" %></li>
 </ul>
 
-<%= link_to t(".delete_account"), account_path, { :method => :delete, :class => "btn btn-danger", :data => { :confirm => t(".confirm_delete") } } %>
+<% if current_user.deletion_allowed? %>
+  <%= link_to t(".delete_account"), account_path, { :method => :delete, :class => "btn btn-danger", :data => { :confirm => t(".confirm_delete") } } %>
+<% else %>
+  <div class="alert alert-warning">
+    <%= t ".recent_editing_html", :time => friendly_date(current_user.deletion_allowed_at) %>
+  </div>
+  <button class="btn btn-secondary" disabled><%= t(".delete_account") %></button>
+<% end %>
+
 <%= link_to t(".cancel"), edit_account_path, :class => "btn btn-link" %>
index cedfc81ea5ce34310cac041136bf9d5a39030f4f..b53061d4c347695c0d449d7d509e90792f683bbe 100644 (file)
@@ -1,7 +1,5 @@
 xml.instruct! :xml, :version => "1.0"
 
-# basic attributes
-
 xml.osm(OSM::API.new.xml_root_attributes) do |osm|
   osm << render(@changeset)
 end
index c68a76da3bcf5da5746f2f28e7a61d9dc4b42cfb..5ff7e262044032609666cd2deeada933bb917fb6 100644 (file)
@@ -1,7 +1,5 @@
 xml.instruct! :xml, :version => "1.0"
 
-# basic attributes
-
 xml.osm(OSM::API.new.xml_root_attributes) do |osm|
   @changesets.each do |changeset|
     osm << render(changeset)
index fb5c018392364bb4e5f945c4d7d6f36c2de5afcb..55f37782da4fa8ce6ec8aa9c7b4572b45ae7aa5c 100644 (file)
@@ -1,4 +1,4 @@
-<header class="closed clearfix">
+<header class="d-flex text-nowrap closed">
   <h1 class="m-0 fw-semibold">
     <a href="<%= root_path %>" class="text-black text-decoration-none geolink">
       <%= image_tag "osm_logo.png", :srcset => image_path("osm_logo.svg"), :alt => t("layouts.logo.alt_text"), :width => 30, :height => 30, :class => "logo" %>
@@ -80,7 +80,7 @@
       </li>
     </ul>
     <% if current_user && current_user.id %>
-      <div class='d-inline-flex dropdown user-menu logged-in clearfix'>
+      <div class='d-inline-flex dropdown user-menu logged-in'>
         <button class='dropdown-toggle btn btn-outline-secondary border-grey bg-white text-secondary px-2 py-1 flex-grow-1' type='button' data-bs-toggle='dropdown'>
           <%= user_thumbnail_tiny(current_user, :width => 25, :height => 25, :class => "user_thumbnail_tiny rounded-1") %>
           <%= render :partial => "layouts/inbox" %>
index 08d3236bfd21dc6a328d8acdbf9320f1053b7273..80871151fa501761b7a6e6e938a5fc38f3f88653 100644 (file)
@@ -67,4 +67,7 @@ Rails.application.configure do
 
   # Use the test adapter for ActiveJob during testing.
   config.active_job.queue_adapter = :test
+
+  # Allow FactoryBot to set primary key attributes
+  config.factory_bot.reject_primary_key_attributes = false
 end
index c1cc522a5e13b24eef5b2bae373c512d403b82f6..f36e6ac1ac4f0686dc401f928c552fe1695478b4 100644 (file)
@@ -79,6 +79,7 @@ Config.setup do |config|
     required(:max_number_of_relation_members).filled(:int?)
     required(:max_issues_count).filled(:int?)
     required(:api_timeout).filled(:int?)
+    required(:user_account_deletion_delay).maybe(:number?)
     required(:imagery_blacklist).maybe(:array?)
     required(:status).filled(:str?, :included_in? => ALLOWED_STATUS)
     required(:avatar_storage).filled(:str?)
diff --git a/config/initializers/r2.rb b/config/initializers/r2.rb
deleted file mode 100644 (file)
index 4f951b3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-require "r2"
-
-class R2ScssProcessor < SassC::Rails::ScssTemplate
-  def self.call(input)
-    output = super(input)
-    data = R2.r2(output[:data])
-    output.delete(:map)
-    output.merge(:data => data)
-  end
-end
-
-Rails.application.config.assets.configure do |env|
-  env.register_mime_type "text/r2+scss", :extensions => [".r2.scss"]
-  env.register_transformer "text/r2+scss", "text/css", R2ScssProcessor
-  env.register_preprocessor "text/r2+scss", Sprockets::DirectiveProcessor.new(:comments => ["//", ["/*", "*/"]])
-end
diff --git a/config/initializers/rtlcss.rb b/config/initializers/rtlcss.rb
new file mode 100644 (file)
index 0000000..11e4e0d
--- /dev/null
@@ -0,0 +1,16 @@
+require "rtlcss"
+
+class RtlcssSCSSProcessor < SassC::Rails::ScssTemplate
+  def self.call(input)
+    output = super(input)
+    data = Rtlcss.flip_css(output[:data])
+    output.delete(:map)
+    output.merge(:data => data)
+  end
+end
+
+Rails.application.config.assets.configure do |env|
+  env.register_mime_type "text/rtlcss+scss", :extensions => [".rtlcss.scss"]
+  env.register_transformer "text/rtlcss+scss", "text/css", RtlcssSCSSProcessor
+  env.register_preprocessor "text/rtlcss+scss", Sprockets::DirectiveProcessor.new(:comments => ["//", ["/*", "*/"]])
+end
index 4446fbe6ec84d87af801d8ccbff931010b70b85f..0737c9b9d2ab02ae2e091528c7af30ad2c2e7930 100644 (file)
@@ -8,8 +8,8 @@ mapnik:
   - { min_zoom: 13, max_zoom: 19, name: bridleway, image: bridleway.png }
   - { min_zoom: 13, max_zoom: 19, name: cycleway, image: cycleway.png }
   - { min_zoom: 13, max_zoom: 19, name: footway, image: footway.png }
-  - { min_zoom: 8, max_zoom: 12, name: rail, image: rail.png }
-  - { min_zoom: 13, max_zoom: 19, name: rail, image: rail13.png }
+  - { min_zoom: 8, max_zoom: 11, name: rail, image: rail.png }
+  - { min_zoom: 12, max_zoom: 19, name: rail, image: rail12.png }
   - { min_zoom: 13, max_zoom: 19, name: subway, image: subway.png }
   - { min_zoom: 13, max_zoom: 19, name: tram, image: tram.png }
   - { min_zoom: 12, max_zoom: 19, name: cable, image: cable.png }
@@ -38,7 +38,7 @@ mapnik:
   - { min_zoom: 12, max_zoom: 19, name: school, image: school.png }
   - { min_zoom: 12, max_zoom: 19, name: building, image: building.png }
   - { min_zoom: 12, max_zoom: 19, name: station, image: station.png }
-  - { min_zoom: 12, max_zoom: 19, name: summit, image: summit.png }
+  - { min_zoom: 11, max_zoom: 19, name: summit, image: summit.png }
   - { min_zoom: 12, max_zoom: 19, name: tunnel, image: tunnel.png }
   - { min_zoom: 13, max_zoom: 19, name: bridge, image: bridge.png }
   - { min_zoom: 15, max_zoom: 19, name: private, image: private.png }
index 3e7e844c9fa27325dbae243fc78e2f59a8d0ebb1..43196a2b5ef670de637c0fe9650fe22bb6cf2ffb 100644 (file)
@@ -23,6 +23,7 @@
 # Author: Karim185.3
 # Author: Kassem7899
 # Author: Kuwaity26
+# Author: LaMagiaaa
 # Author: MRidhaAJ
 # Author: Majid Al-Dharrab
 # Author: McDutchie
@@ -1950,10 +1951,10 @@ ar:
       community_driven_community_blogs: مدونات المجتمع
       community_driven_osm_foundation: مؤسسة OSM
       open_data_title: البيانات المفتوحة
-      open_data_1_html: 'OpenStreetMap هو %{open_data}: أنت حر في استخدامه لأي غرض!
-        N! طالما أنك تنسب إلى OpenStreetMap والمساهمين فيه. إذا قمت بتعديل أو! N!
-        Ø¨Ù\86اء Ø¹Ù\84Ù\89 Ø§Ù\84بÙ\8aاÙ\86ات Ø¨Ø·Ø±Ù\82 Ù\85عÙ\8aÙ\86Ø© Ø\8c Ù\81Ù\8aجÙ\88ز Ù\84Ù\83 ØªÙ\88زÙ\8aع Ø§Ù\84Ù\86تÙ\8aجة Ù\81Ù\82Ø·! N! ØªØ­Øª Ù\86Ù\81س Ø§Ù\84ترخÙ\8aص.
-        راجع %{copyright_license_link} للحصول على التفاصيل.'
+      open_data_1_html: "\nOpenStreetMap هو %{open_data}: أنت حر في استخدامه لأي غرض\n
+        طالما أنك تنسب إلى OpenStreetMap والمساهمين فيه. إذا قمت بتعديل أو \n بناء
+        Ø¹Ù\84Ù\89 Ø§Ù\84بÙ\8aاÙ\86ات Ø¨Ø·Ø±Ù\82 Ù\85عÙ\8aÙ\86Ø© Ø\8c Ù\81Ù\8aجÙ\88ز Ù\84Ù\83 ØªÙ\88زÙ\8aع Ø§Ù\84Ù\86تÙ\8aجة Ù\81Ù\82Ø·\nتحت Ù\86Ù\81س Ø§Ù\84ترخÙ\8aص. Ø±Ø§Ø¬Ø¹
+        %{copyright_license_link} للحصول على التفاصيل."
       open_data_open_data: البيانات المفتوحة
       open_data_copyright_license: صفحة حقوق النشر والترخيص
       legal_title: قانوني
index b9a4881cea81751621a422224ff47aa2bc393383..6390710480c5bd6c3d08b1cf48c97d31d645e3f1 100644 (file)
@@ -2082,6 +2082,7 @@ bn:
       andy_allan: অ্যান্ডি অ্যালান
     site:
       edit_tooltip: মানচিত্রটি সম্পাদনা করুন
+      embed_html_disabled: এই মানচিত্রের স্তরের জন্য এইচটিএমএল এম্বেডিং উপলব্ধ নয়।
     changesets:
       show:
         comment: মন্তব্য
index f7ce20268e166cdd4e41e4681301ad34fd2f1f6d..5f0cbf9bab1ccb9480a6ad670a789d77a4a9851b 100644 (file)
@@ -2063,6 +2063,7 @@ br:
           Degas a reomp da soñj da genlabourerien OSM ne zleont morse lakaat roadennoù a zeu
           eus mammennoù dindan wirioù (da sk. : Google Maps pe kartennoù moullet) hep aotre
           ezpleg ar re zo ar gwirioù-aozer ganto.
+        trademarks_title: Merkoù marilhet
         trademarks_1_1_trademark_policy: Politikerezh e-keñver ar merkoù
     index:
       js_1: Pe emaoc'h oc'h implijout ur merdeer ha ne skor ket JavaScript, pe hoc'h
index f98a78a3156796c34d9bebb0d564628a847d2c8a..8b0745118b4adfa2fb06f9e16efbe5414bf17e0e 100644 (file)
@@ -256,6 +256,7 @@ en:
         retain_notes: Your map notes and note comments, if any, will be retained but hidden from view.
         retain_changeset_discussions: Your changeset discussions, if any, will be retained.
         retain_email: Your email address will be retained.
+        recent_editing_html: "As you have edited recently your account cannot currently be deleted. Deletion will be possible in %{time}."
         confirm_delete: Are you sure?
         cancel: Cancel
   accounts:
@@ -3034,6 +3035,7 @@ en:
       map_data_zoom_in_tooltip: Zoom in to see map data
       queryfeature_tooltip: Query features
       queryfeature_disabled_tooltip: Zoom in to query features
+      embed_html_disabled: HTML embedding is not available for this map layer
     changesets:
       show:
         comment: "Comment"
index 9c9239ad4746ab6dbeab4992f8bc7449efe26f3a..21b1bf5f60f632119866a7870b8a236a3ae2ebc6 100644 (file)
@@ -264,6 +264,7 @@ fi:
       openid: OpenID
       google: Google
       facebook: Facebook
+      microsoft: Microsoft
       github: GitHub
       wikipedia: Wikipedia
   api:
@@ -2006,6 +2007,7 @@ fi:
           Resources Canada), ja StatCanista (Geography Division,
           Statistics Canada).
         contributors_ca_canada: Kanada
+        contributors_cz_czechia: Tšekki
         contributors_fi_credit_html: '%{finland}: Sisältää karttatietoja Maanmittauslaitoksen
           maastotietokannasta ja muista lähteistä %{nlsfi_license_link} mukaisesti.'
         contributors_fi_finland: Suomi
index d3f258a5b911c94335634733767ca15183b578d3..9455837ae284ddb615be1a28f12198ca1b36b7b4 100644 (file)
@@ -365,6 +365,9 @@ fr:
         retain_changeset_discussions: Vos discussions sur les groupes de modification,
           s’il y en a, seront conservées.
         retain_email: Votre adresse de courriel sera conservée.
+        recent_editing_html: Comme vous avez récemment fait des modifications, votre
+          compte ne peut pas être supprimé pour le moment. La suppression sera possible
+          dans %{time}.
         confirm_delete: Êtes-vous sûr(e) ?
         cancel: Annuler
   accounts:
@@ -3287,6 +3290,8 @@ fr:
       map_data_zoom_in_tooltip: Zoomez pour lire voir les données sur la carte
       queryfeature_tooltip: Interroger les objets
       queryfeature_disabled_tooltip: Zoomer plus pour rechercher des objets
+      embed_html_disabled: L’intégration de HTML n’est pas disponible pour cette couche
+        de carte
     changesets:
       show:
         comment: Commenter
index 95e7740f7b8e5b12ecc038fb740140c090777001..78079f7e19cf8c2ffc7ce1bd52d227bfc9af3521 100644 (file)
@@ -283,6 +283,8 @@ gl:
         retain_changeset_discussions: Conservaremos os teus conxuntos de modificacións,
           se os hai.
         retain_email: Conservaremos o teu enderezo de correo electrónico.
+        recent_editing_html: Como editaches hai pouco, a túa conta non se pode eliminar
+          nestes intres. A eliminación será posible en %{time}.
         confirm_delete: Queres continuar?
         cancel: Cancelar
   accounts:
index 32d6dca09905355aee904194a853bcafa3aa0a51..1b1d01f95c91dd96c5d91f89dd7f8ae99a421c53 100644 (file)
@@ -320,6 +320,8 @@ he:
         retain_changeset_discussions: הדיונים שלכם על ערכות השינויים, אם יש כאלה,
           יישמרו.
         retain_email: כתובת הדואר האלקטרוני שלך תישמר.
+        recent_editing_html: כיוון שערכת לאחרונה אין אפשרות למחוק את החשבון שלך. אפשר
+          יהיה למחוק אותו בעוד %{time}.
         confirm_delete: להמשיך?
         cancel: ביטול
   accounts:
@@ -2807,12 +2809,15 @@ he:
       role:
         administrator: לחשבון הזה יש הרשאות מפעיל
         moderator: זהו חשבון מנהל
+        importer: המשתמש הזה הוא מייבא
         grant:
           administrator: הענקת הרשאות מפעיל
           moderator: הענקת הרשאות מנהל
+          importer: הענקת גישת מייבא
         revoke:
           administrator: שלילת הרשאות מפעיל
           moderator: שלילת הרשאות מנהל
+          importer: שלילת גישת מייבא
       block_history: חסימות פעילות
       moderator_history: חסימות שניתנו
       comments: הערות
index 36d0cfcb4c2aef06162df32512e8d429a4d50510..b9ade646979523abb22ba43f2e5d78d29a48399c 100644 (file)
@@ -215,8 +215,8 @@ hi:
         one: '%{count} महीने पहले'
         other: '%{count} महीने पहले'
       x_years:
-        one: '%{count} à¤¸à¤¾à¤² पहले'
-        other: '%{count} à¤¸à¤¾à¤² पहले'
+        one: '%{count} à¤µà¤°à¥\8dष पहले'
+        other: '%{count} à¤µà¤°à¥\8dष पहले'
   editor:
     default: डिफ़ॉल्ट (currently %{name})
     id:
index 12e5025452cbced0d835b10faf29d36c254dbbb3..5281dd4ab9db1be483e675ea68119b7e147866af 100644 (file)
@@ -269,6 +269,9 @@ ia:
         retain_changeset_discussions: Tu discussiones sur gruppos de modificationes,
           si existe, essera retenite.
         retain_email: Tu adresse de e-mail essera retenite.
+        recent_editing_html: Post que tu ha recentemente apportate modificationes,
+          tu conto non pote esser delite al momento. Le deletion essera possibile
+          in %{time}.
         confirm_delete: Es tu secur?
         cancel: Cancellar
   accounts:
index 1a2964d2073224d735a8dfc44ce12ea0f09a0b6a..21f4cd062a1c6894919d0344f3d2eb8154539990 100644 (file)
@@ -39,6 +39,7 @@ kn:
         update: ನವೀಕರಿಸಿ
       trace:
         create: ಅಪ್ಲೋಡ್
+        update: ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಿ
   activerecord:
     errors:
       messages:
@@ -121,6 +122,7 @@ kn:
         home_lon: ರೇಖಾಂಶ
         languages: ಅದ್ಯತೆಯ ಭಾಷೆಗಳು
         pass_crypt: ಪ್ರವೇಶಪದ
+        pass_crypt_confirmation: ಪ್ರವೇಶಪದವನ್ನು ಧೃಡೀಕರಿಸಿ
   datetime:
     distance_in_words_ago:
       about_x_hours:
@@ -146,8 +148,8 @@ kn:
         one: ೧ ಸೆಕೆಂಡ್ ಹಿಂದೆ
         other: '%{count} ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ'
       x_minutes:
-        one: ೧ ಮಿನಿಟ್ ಹಿಂದೆ
-        other: '%{count} à²®à²¿à²¨à²¿à²\9fà³\81ಗಳ ಹಿಂದೆ'
+        one: '%{count} ನಿಮಿಷದ ಹಿಂದೆ'
+        other: '%{count} à²¨à²¿à²®à²¿à²·ಗಳ ಹಿಂದೆ'
       x_days:
         one: ೧ ದಿನದ ಹಿಂದೆ
         other: '%{count} ದಿನಗಳ ಹಿಂದೆ'
@@ -168,9 +170,10 @@ kn:
   auth:
     providers:
       none: ಯಾವುದೂ ಇಲ್ಲ
+      openid: ಓಪನ್ ಐಡಿ
       google: ಗೂಗಲ್
       facebook: ಫೇಸ್‍ಬುಕ್
-      microsoft: à²µà²¿à²\82ಡà³\8bಸà³\8d à²²à³\88ವ
+      microsoft: à²®à³\88à²\95à³\8dರà³\8bಸಾಫà³\8dà²\9f
       github: ಗಿಟ್‌ಹಬ್
       wikipedia: ವಿಕಿಪೀಡಿಯ
   api:
@@ -204,6 +207,16 @@ kn:
       external auth: ಬಾಹ್ಯ ದೃಢೀಕರಣ
       openid:
         link text: ಇದು ಏನು?
+      public editing:
+        enabled link text: ಇದು ಏನು?
+      contributor terms:
+        link text: ಇದು ಏನು?
+      save changes button: ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಿ
+      delete_account: ಖಾತೆಯನ್ನು ಅಳಿಸಿ
+    go_public:
+      heading: ಸಾರ್ವಜನಿಕ ಸಂಪಾದನೆ
+    destroy:
+      success: ಖಾತೆಯನ್ನು ಅಳಿಸಲಾಗಿದೆ.
   browse:
     created: ಸೃಷ್ಟಿಸಲ್ಪಟ್ಟ
     closed: ಮುಚ್ಚಲಾಗಿದೆ
@@ -319,6 +332,7 @@ kn:
       km away: '%{count} ಕಿಮೀ ದೂರ'
       m away: '%{count} ಮೀ ದೂರ'
     popup:
+      your location: ನಿಮ್ಮ ಸ್ಥಳ
       friend: ಗೆಳೆಯ
     show:
       my friends: ನನ್ನ ಗೆಳೆಯರು
@@ -337,6 +351,7 @@ kn:
       in_language_title: ದಿನಚರಿ ದಾಖಲಾತಿ %{language}ನಲ್ಲಿ
       new: ಹೊಸದಾದ ದಿನಚರಿ ದಾಖಲು
       new_title: ನನ್ನ ಬಳಕೆದಾರ ದಿನಚರಿಯಲ್ಲಿ ಹೊಸ ದಾಖಲಾತಿ ನಿರ್ಮಿಸಿ
+      my_diary: ನನ್ನ ಡೈರಿ
       no_entries: ದಿನಚರಿ ದಾಖಲಾತಿಗಳಿಲ್ಲ
       recent_entries: ಇತ್ತೀಚೆಗಿನ ದಿನಚರಿ ದಾಖಲಾತಿಗಳು
       older_entries: ಹಳೆಯ ದಾಖಲಾತಿಗಳು
@@ -382,15 +397,22 @@ kn:
       comment: ಟಿಪ್ಪಣಿ
       newer_comments: ಹೊಸ ಟಿಪ್ಪಣಿಗಳು
       older_comments: ಹಳೆ ಟಿಪ್ಪಣಿಗಳು
+  friendships:
+    make_friend:
+      button: ಸ್ನೇಹಿತರಾಗಿ ಸೇರಿಸಿ
   geocoder:
     search_osm_nominatim:
       prefix:
+        aeroway:
+          helipad: ಹೆಲಿಪ್ಯಾಡ್
         amenity:
+          arts_centre: ಕಲಾ ಕೇಂದ್ರ
           atm: ಎಟಿಎಂ
           bank: ಬ್ಯಾಂಕ್
           bar: ಬಾರ್
           bench: ‍ಬೆಂಚ್
           bicycle_parking: ‍‍ಸೈಕಲ್ ನಿಲುಗಡೆ
+          brothel: ವೇಶ್ಯಾಗೃಹ
           bus_station: ಬಸ್ ನಿಲ್ದಾಣ
           cafe: ಕೆಫೆ
           car_rental: ಬಾಡಿಗೆ ಕಾರು
@@ -410,7 +432,8 @@ kn:
           ferry_terminal: ‍‍ಹಾಯಿದೋಣಿ ನಿಲ್ದಾಣ
           fire_station: ‍‍ಅಗ್ನಿಶಾಮಕ ಠಾಣೆ
           fountain: ‍ಕಾರಂಜಿ
-          fuel: ‍ಇಂಧನ
+          fuel: ಪೆಟ್ರೊಲ್ ಪಂಪ್
+          gambling: ಜೂಜಾಟ
           grave_yard: ಸ್ಮಾಶಾನ
           hospital: ಆಸ್ಪತ್ರೆ
           ice_cream: ‍ಐಸ್ ಕ್ರೀಂ
@@ -418,17 +441,20 @@ kn:
           library: ಗ್ರಂಥಾಲಯ
           marketplace: ‍‍ಮಾರುಕಟ್ಟೆ
           monastery: ‍‍ಮಠ
+          parking: ಪಾರ್ಕಿಂಗ್
           pharmacy: ‍‍ಔ‍ಷಧಾಲಯ
           place_of_worship: ‍‍ಆರಾಧನಾ ಮಂದಿರ
           police: ಆರಕ್ಷಕ
           post_box: ಟಪಾಲು
           post_office: ಅಂಚೆ ಕಛೇರಿ
           prison: ಕಾರಾಗೃಹ
+          pub: ಪಬ್
           public_building: ಸಾರ್ವಜನಿಕ ಕಟ್ಟಡ
           restaurant: ‍‍ರೆಸ್ಟೋರೆಂಟ್
           school: ಶಾಲೆ
           social_centre: ಸಾಮಾಜಿಕ ತಾಣ
           swimming_pool: ಈಜು ಕೊಳ
+          taxi: ಟ್ಯಾಕ್ಸಿ
           theatre: ಕಲಾಭವನ
           toilets: ಶೌಚಾಲಯ
           townhall: ‍‍‍‍ಪುರಭವನ
@@ -444,12 +470,24 @@ kn:
         bridge:
           "yes": ಸೇತುವೆ
         building:
+          bungalow: ಬಂಗಲೆ
+          hospital: ಆಸ್ಪತ್ರೆ ಕಟ್ಟಡ
+          hotel: ಹೋಟೆಲ್ ಕಟ್ಟಡ
+          house: ಮನೆ
+          houseboat: ಹೌಸ್ ಬೋಟ್
+          hut: ಗುಡಿಸಲು
+          industrial: ಕೈಗಾರಿಕಾ ಕಟ್ಟಡ
+          kindergarten: ಶಿಶುವಿಹಾರ ಕಟ್ಟಡ
+          manufacture: ಉತ್ಪಾದನಾ ಕಟ್ಟಡ
+          office: ಕಚೇರಿ ಕಟ್ಟಡ
           public: ಸಾರ್ವಜನಿಕ ಕಟ್ಟಡ
+          residential: ವಸತಿ ಕಟ್ಟಡ
           roof: ಛಾವಣಿ
           school: ಶಾಲಾ ಕಟ್ಟಡ
           "yes": ಕಟ್ಟಡ
         craft:
           carpenter: ಬಡಗಿ
+          electrician: ಎಲೆಕ್ಟ್ರಿಷಿಯನ್
           photographer: ಛಾಯಾಗ್ರಾಹಕ
           tailor: ‍‍‍ದರ್ಜಿ
           "yes": ‍‍‍‍ಕರಕುಶಲ ಅಂಗಡಿಯು
@@ -478,13 +516,17 @@ kn:
           railway: ಐತಿಹಾಸಿಕ ರೈಲ್ವೆ
           roman_road: ರೋಮನ್ ರಸ್ತೆ
           stone: ಕಲ್ಲು
+          tomb: ಸಮಾಧಿ
           tower: ಗೋಪುರ
+        junction:
+          "yes": ಜಂಕ್ಷನ್
         landuse:
           cemetery: ಸ್ಮಶಾನ
           forest: ಅರಣ್ಯ
           grass: ‍ಹುಲ್ಲು
           mine: ಗಣಿ
           orchard: ತೋಟ
+          reservoir: ಜಲಾಶಯ
         leisure:
           dog_park: ಶ್ವಾನ ಉದ್ಯಾನ
           garden: ತೋಟ
@@ -527,9 +569,12 @@ kn:
           administrative: ಆಡಳಿತ
           architect: ವಾಸ್ತುಶಿಲ್ಪಿ
           company: ಕಂಪನಿ
+          educational_institution: ಶೈಕ್ಷಣಿಕ ಸಂಸ್ಥೆ
+          employment_agency: ಉದ್ಯೋಗ ಸಂಸ್ಥೆ
           government: ಸರ್ಕಾರಿ ಕಛೇರಿ
           lawyer: ವಕೀಲ
           ngo: ಸರ್ಕಾರೇತರ ಕಛೇರಿ
+          tax_advisor: ತೆರಿಗೆ ಸಲಹೆಗಾರರು
           "yes": ಕಛೇರಿ
         place:
           archipelago: ದ್ವೀಪ ಸಮೂಹ
@@ -549,6 +594,7 @@ kn:
           halt: ರೈಲು ನಿಲ್ದಾಣ
           junction: ರೈಲು ಜಂಕ್ಷನ್
           monorail: ಮೊನೊರೈಲು
+          rail: ರೈಲು
           station: ರೈಲು ನಿಲ್ದಾಣ
           stop: ರೈಲು ನಿಲ್ದಾಣ
         shop:
@@ -562,11 +608,13 @@ kn:
           chocolate: ಚಾಕೊಲೇಟ್
           clothes: ಬಟ್ಟೆಯ ಅಂಗಡಿ
           computer: ಗಣಕಯಂತ್ರದ ಅಂಗಡಿ
+          dairy: ಡೈರಿ ಅಂಗಡಿ
           florist: ಹೂವಿನಂಗಡಿ
           furniture: ‍‍‍‍‍ಪೀಠೋಪಕರಣ
           general: ಕಿರಾಣಿ ಅಂಗಡಿ
           gift: ಉಡುಗೊರೆ ಅಂಗಡಿ
           jewelry: ಆಭರಣಗಳ ಆಂಗಡಿ
+          kitchen: ಅಡುಗೆ ಅಂಗಡಿ
           "yes": ಅಂಗಡಿ
         tourism:
           hostel: ‍ವಸತಿ ನಿಲಯ
@@ -599,8 +647,15 @@ kn:
     index:
       search: ಹುಡುಕು
       user_not_found: ಬಳಕೆದಾರ ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ
+      status: ಸ್ಥಿತಿಗತಿ
       reports: ವರದಿಗಳು
+      last_updated: ಕೊನೆಯ ಬದಲಾವಣೆ
+      states:
+        open: ತೆರೆ
+        resolved: ಪರಿಹರಿಸಲಾಗಿದೆ
     show:
+      resolve: ಪರಿಹರಿಸಿ
+      ignore: ನಿರ್ಲಕ್ಷಿಸಿ
       new_reports: ಹೊಸ ವರದಿಗಳು
   reports:
     new:
@@ -625,10 +680,13 @@ kn:
     export_data: ದತ್ತಾಂಶ ರಫ್ತುಮಾಡು
     intro_header: ಒಪನ್ ಸ್ಟ್ರೀಟ್ ಮ್ಯಾಪ್ ಗೆ  ಸುಸ್ವಾಗತ!
     intro_2_create_account: ಹೊಸ ಬಳಕೆದಾರ ಖಾತೆಯನ್ನು ರಚಿಸಿ
+    partners_ucl: ಯುಸಿಎಲ್
+    partners_bytemark: ಬೈಟ್ಮಾರ್ಕ್ ಹೋಸ್ಟಿಂಗ್
     tou: ಬಳಕೆಯ ನಿಬಂಧನೆಗಳು
     help: ಸಹಾಯ
     about: ನಮ್ಮ ಬಗ್ಗೆ
     copyright: ಕಾಯ್ದಿರಿಸಿದ ಹಕ್ಕುಗಳು
+    communities: ಸಮುದಾಯಗಳು
     community: ಸಮುದಾಯ
     community_blogs: ಸಮುದಾಯದ ಬ್ಲಾಗ್ ಗಳು
     make_a_donation:
@@ -651,6 +709,11 @@ kn:
       greeting: ನಮಸ್ತೆ,
     changeset_comment_notification:
       greeting: ನಮಸ್ತೆ,
+  confirmations:
+    confirm:
+      button: ಧೃಡಪಡಿಸಿ
+    confirm_email:
+      button: ಧೃಡಪಡಿಸಿ
   messages:
     inbox:
       from: ಇಂದ
@@ -662,6 +725,9 @@ kn:
     new:
       title: ಸಂದೇಶ ಕಳುಹಿಸಿ
       send_message_to_html: ಹೊಸ ಸಂದೇಶವನ್ನು %{name} ಗೆ ಕಳುಹಿಸಿ
+    no_such_message:
+      title: ಅಂತಹ ಯಾವುದೇ ಸಂದೇಶವಿಲ್ಲ
+      heading: ಅಂತಹ ಯಾವುದೇ ಸಂದೇಶವಿಲ್ಲ
     outbox:
       to: ಗೆ
       subject: ವಿಷಯ
@@ -688,15 +754,35 @@ kn:
   preferences:
     show:
       title: ನನ್ನ ಪ್ರಾಶಸ್ತ್ಯಗಳು
+      preferred_languages: ಅದ್ಯತೆಯ ಭಾಷೆಗಳು
+      edit_preferences: ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಸಂಪಾದಿಸಿ
+    edit:
+      title: ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಸಂಪಾದಿಸಿ
   profiles:
     edit:
       image: ಚಿತ್ರ
+      show: ತೋರಿಸಿ
+      delete: ಅಳಿಸಿ
   sessions:
     new:
       title: ಲಾಗ್ ಇನ್
       heading: ಲಾಗಿನ್
       password: 'ಪ್ರವೇಶಪದ:'
       login_button: ಲಾಗಿನ್
+      auth_providers:
+        google:
+          title: ಗೂಗಲ್ ಮೂಲಕ ಲಾಗಿನ್ ಆಗಿರಿ
+          alt: ಗೂಗಲ್ ಓಪನ್ ಐಡಿಯೊಂದಿಗೆ ಲಾಗಿನ್ ಮಾಡಿ
+        facebook:
+          title: ಫೇಸ್ಬುಕ್ ಮೂಲಕ ಲಾಗಿನ್ ಆಗಿರಿ
+          alt: ಫೇಸ್ಬುಕ್ ಖಾತೆಯೊಂದಿಗೆ ಲಾಗಿನ್ ಮಾಡಿ
+        microsoft:
+          alt: ಮೈಕ್ರೋಸಾಫ್ಟ್ ಖಾತೆಯೊಂದಿಗೆ ಪ್ರವೇಶಿಸಿ
+        github:
+          alt: ಗಿಟ್ಹಬ್ ಖಾತೆಯೊಂದಿಗೆ ಲಾಗಿನ್ ಮಾಡಿ
+        wikipedia:
+          title: ವಿಕಿಪೀಡಿಯದೊಂದಿಗೆ ಪ್ರವೇಶಿಸಿ
+          alt: ವಿಕಿಪೀಡಿಯ ಖಾತೆಯೊಂದಿಗೆ ಪ್ರವೇಶಿಸಿ
     destroy:
       title: ಲಾಗ್ ಔಟ್
       logout_button: ಲಾಗ್ ಔಟ್
@@ -717,6 +803,7 @@ kn:
   site:
     about:
       next: ಮುಂದಿನ
+      local_knowledge_title: ಸ್ಥಳೀಯ ಜ್ಞಾನ
       open_data_title: ಮುಕ್ತ ದತ್ತಾಂಶ
     copyright:
       foreign:
@@ -727,6 +814,19 @@ kn:
         mapping_link: ನಕ್ಷೆಯನ್ನು ಸಂಪಾದಿಸಿಲು ಪ್ರಾರಂಭಿಸಿ
       legal_babble:
         title_html: ಕೃತಿಸ್ವಾಮ್ಯ ಮತ್ತು ಪರವಾನಗಿ
+        contributors_at_austria: ಆಸ್ಟ್ರಿಯಾ
+        contributors_au_australia: ಆಸ್ಟ್ರೇಲಿಯಾ
+        contributors_ca_canada: ಕೆನಡಾ
+        contributors_cz_czechia: ಜೆಕಿಯಾ
+        contributors_fi_finland: ಫಿನ್ಲ್ಯಾಂಡ್
+        contributors_fr_france: ಫ಼್ರಾನ್ಸ್
+        contributors_nl_netherlands: ನೆದರ್ಲೆಂಡ್
+        contributors_nz_new_zealand: ನ್ಯೂಜಿಲ್ಯಾಂಡ್
+        contributors_rs_serbia: ಸರ್ಬಿಯಾ
+        contributors_si_slovenia: ಸ್ಲೊವೆನಿಯಾ
+        contributors_es_spain: ಸ್ಪೇನ್
+        contributors_za_south_africa: ದಕ್ಷಿಣ ಆಫ್ರಿಕಾ
+        contributors_gb_united_kingdom: ಯುನೈಟೆಡ್ ಕಿಂಗ್ಡಮ್
     export:
       title: ರಫ್ತು ಮಾಡು
       licence: ಪರವಾನಗಿ
@@ -792,11 +892,23 @@ kn:
   traces:
     new:
       help: ಸಹಾಯ
+  oauth_clients:
+    show:
+      edit: ವಿವರಗಳನ್ನು ಸಂಪಾದಿಸಿ
+  oauth2_applications:
+    application:
+      edit: ಸಂಪಾದಿಸಿ
+      delete: ಅಳಿಸಿ
+    show:
+      edit: ಸಂಪಾದಿಸಿ
   users:
     terms:
       legale_names:
         france: ಫ಼್ರಾನ್ಸ್
         italy: ಇಟಲಿ
+    show:
+      my messages: ನನ್ನ ಸಂದೇಶಗಳು
+      edits: ಸಂಪಾದನೆಗಳು
   user_blocks:
     show:
       created: 'ಸೃಷ್ಟಿಸಲ್ಪಟ್ಟಿದೆ:'
index d641c5659e1f583b8576be14d906e4febc475859..842c10b9a59b8791a4a3793b2fa0b316cc047665 100644 (file)
@@ -267,6 +267,8 @@ mk:
         retain_notes: Вашите белешки и коментари на картата (но нема да бидат видливи).
         retain_changeset_discussions: Вашите разговори за збировите промени.
         retain_email: Вашите е-поштенски адреси.
+        recent_editing_html: Бидејќи неодамна уредувавте, вашата сметка засега не
+          може да се избрише. Бришењето ќе може да се изведе за %{time}.
         confirm_delete: Дали сте сигурни?
         cancel: Откажи
   accounts:
@@ -3099,6 +3101,7 @@ mk:
       map_data_zoom_in_tooltip: Приближете за да ги видите податоците
       queryfeature_tooltip: Пребарување на елементи
       queryfeature_disabled_tooltip: Зголеми на пребарувањето на елементи
+      embed_html_disabled: Вградувањето на HTML не е достапно за овој слој на картата
     changesets:
       show:
         comment: Коментирај
index 377969bcab4ce18792fe23add1ec5175b31d77c1..2b66ed4173b420d1b82e2dfb27eca681470e6c53 100644 (file)
@@ -325,6 +325,9 @@ nl:
         retain_changeset_discussions: Uw overleg over wijzigingensets, indien van
           toepassing, blijft behouden.
         retain_email: Uw e-mailadres blijft behouden.
+        recent_editing_html: Omdat u onlangs bewerkingen hebt aangebracht, kan uw
+          account momenteel niet worden verwijderd. Verwijderen is pas over %{time}
+          mogelijk.
         confirm_delete: Weet u het zeker?
         cancel: Annuleren
   accounts:
@@ -2880,12 +2883,15 @@ nl:
       role:
         administrator: Deze gebruiker is beheerder
         moderator: Deze gebruiker is moderator
+        importer: Deze gebruiker is een importeur
         grant:
           administrator: Beheerdersrechten toekennen
           moderator: Moderatorrechten toekennen
+          importer: Importeurstoegang verlenen
         revoke:
           administrator: Beheerdersrechten intrekken
           moderator: Moderatorrechten intrekken
+          importer: Importeurstoegang intrekken
       block_history: Actieve blokkades
       moderator_history: Uitgevoerde blokkades
       comments: Reacties
@@ -3186,6 +3192,8 @@ nl:
       map_data_zoom_in_tooltip: Inzoomen om kaartgegevens te bekijken
       queryfeature_tooltip: Nabije objecten opvragen
       queryfeature_disabled_tooltip: Inzoomen om objecten op te vragen
+      embed_html_disabled: Het inbedden van HTML-code is voor deze kaartlaag niet
+        mogelijk
     changesets:
       show:
         comment: Reageren
index 8b24d34e744fd84336f470086e685e1ac6d83080..7d5b6c6cef746787d752c86e1f477e663fa3eadf 100644 (file)
@@ -75,7 +75,7 @@ sc:
       tracetag: Eticheta de su sestadu
       user: Utente
       user_preference: Preferèntzias de s'utente
-      user_token: Còdighe de s'utente
+      user_token: Getone de s'utente
       way: Lìnia
       way_node: Nodu de su caminu
       way_tag: Eticheta de sa lìnia
@@ -274,6 +274,8 @@ sc:
         retain_changeset_discussions: Sos arresonos tuos in sos annantos de modìficas,
           si bi nd'at, s'ant a cunservare.
         retain_email: S'indiritzu tuo de posta eletrònica s'at a cunservare.
+        recent_editing_html: Sende chi as modificadu dae pagu su contu tuo non si
+          podet iscantzellare. Sa cantzelladura at a èssere possìbile in %{time}.
         confirm_delete: Seguru ses?
         cancel: Annulla
   accounts:
@@ -601,10 +603,31 @@ sc:
           de s'utente finale
         interaction_required: Su serbidore de autorizatzione tenet bisòngiu de s'interatzione
           de s'utente finale
+        login_required: Su serbidore de autorizatzione tenet bisòngiu de s'autenticatzione
+          de s'utente finale
     flash:
       applications:
         create:
           notice: Aplicatzione registrada.
+    openid_connect:
+      errors:
+        messages:
+          auth_time_from_resource_owner_not_configured: Errore pro neghe de sa cunfiguratzione
+            mancante de Doorkeeper::OpenidConnect.configure.auth_time_from_resource_owner.
+          reauthenticate_resource_owner_not_configured: Errore pro neghe de sa cunfiguratzione
+            mancante de Doorkeeper::OpenidConnect.configure.reauthenticate_resource_owner.
+          resource_owner_from_access_token_not_configured: Errore pro neghe de sa
+            cunfiguratzione mancante de Doorkeeper::OpenidConnect.configure.resource_owner_from_access_token.
+          select_account_for_resource_owner_not_configured: Errore pro neghe de sa
+            cunfiguratzione mancante de Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner.
+          subject_not_configured: Sa generatzione de su getone ID est fallida pro
+            neghe de sa cunfiguratzione mancante de Doorkeeper::OpenidConnect.configure.subject.
+    scopes:
+      address: Pòmpia s'indiritzu fìsicu tuo
+      email: Pòmpia s'indiritzu de posta eletrònica tuo
+      openid: Autèntica su contu tuo
+      phone: Pòmpia su nùmeru tuo de telèfonu
+      profile: Pòmpia sas informatziones de su profilu tuo
   errors:
     contact:
       contact_url_title: Canales de cuntatu diferentes ispiegados
@@ -2084,6 +2107,12 @@ sc:
           Naturales de su Cànada), e StatCan (Divisione de Geografia,
           Istatìsticas de su Cànada).
         contributors_ca_canada: Cànada
+        contributors_cz_credit_html: '%{czechia}: Cuntenet datos de s''Amministratzione
+          Istatale pro sa Medida de su Terrinu e de su Catastu cun litzèntzia suta
+          de sa %{cc_licence_link}'
+        contributors_cz_czechia: Tzèchia
+        contributors_cz_cc_licence: Litzèntzia internatzionale Creative Commons Atributzione
+          4.0 (CC BY 4.0)
         contributors_fi_credit_html: |-
           %{finland}: Cuntenet datos dae sa
           base de datos topogràficos de su Servìtziu Natzionale de su Territòriu Finlandesu e àteros annantos de datos, suta de sa %{nlsfi_license_link}.
@@ -2622,6 +2651,7 @@ sc:
     permissions:
       missing: No as cuntzèdidu s'atzessu a custa caraterìstica  a s'aplicatzione
     scopes:
+      openid: Intra impreende OpenStreetMap
       read_prefs: Leghe sas preferèntzias de utente
       write_prefs: Modìfica sas preferèntzias de utente
       write_diary: Crea intradas de su diàriu, cummentos e faghe amistades
@@ -2827,12 +2857,15 @@ sc:
       role:
         administrator: Custu utente est un'amministradore
         moderator: Custu utente est unu moderadore
+        importer: Custu impitadore est un'importadore
         grant:
           administrator: Cuntzede s'atzessu comente amministradore
           moderator: Cuntzede s'atzessu comente moderadore
+          importer: Cuntzede s'atzessu comente importadore
         revoke:
           administrator: Rèvoca s'atzessu comente amministradore
           moderator: Rèvoca s'atzessu comente moderadore
+          importer: Rèvoca s'atzessu comente importadore
       block_history: Blocos ativos
       moderator_history: Blocos fatos
       comments: Cummentos
@@ -3104,6 +3137,7 @@ sc:
         cyclosm: CyclOSM
         cycle_map: Mapa tziclìstica
         transport_map: Mapa de sos trasportos
+        tracestracktop_topo: Tracestrack Topo
         hot: Umanitàriu
         opnvkarte: ÖPNVKarte
       layers:
@@ -3123,6 +3157,7 @@ sc:
       andy_allan: Andy Allan
       opnvkarte_credit: Tasseddos frunidos pro cortesia dae %{memomaps_link}
       memomaps: MeMoMaps
+      tracestrack_credit: Tasseddos frunidos pro cortesia dae %{tracestrack_link}
       hotosm_credit: Istile de sos tasseddos de %{hotosm_link} acasagiadu dae %{osm_france_link}
       hotosm_name: Iscuadra umanitària de OpenStreetMap
     site:
index a5c01105967a2f2f6fb941b8be8454c2c100d883..b297330bf639577c04ad4117f232842159186a7c 100644 (file)
@@ -988,7 +988,7 @@ sco:
         stay_roundabout_without_exit: Stay on roondaboot - %{name}
         start_without_exit: Stairt at end o %{name}
         destination_without_exit: Reak destination
-        against_oneway_without_exit: Gae against ane-wey on %{name}
+        against_oneway_without_exit: Gae agin ane-wey on %{name}
         end_oneway_without_exit: End o ane-wey on %{name}
         roundabout_with_exit: At roondaboot tak exit %{exit} ontae %{name}
         unnamed: unnamed road
index e6be76e3db440f4218dc937fd1a491536bfd8c3f..00777d496d581a30081ffbc62c4e159cb8feb2ab 100644 (file)
@@ -298,6 +298,7 @@ zh-TW:
         retain_notes: 若有您的地圖註記與註記評論內容,這將會繼續保留;不過會隱藏起來。
         retain_changeset_discussions: 若有您的變更集討論,這將會繼續保留。
         retain_email: 您的電子郵件地址將會繼續保留。
+        recent_editing_html: 因為您最近有作過編輯,目前無法刪除您的帳號。在 %{time} 後才可刪除。
         confirm_delete: 您確定嗎?
         cancel: 取消
   accounts:
@@ -2888,6 +2889,7 @@ zh-TW:
       map_data_zoom_in_tooltip: 放大以查看地圖圖資
       queryfeature_tooltip: 查詢圖徵
       queryfeature_disabled_tooltip: 放大地圖以查询圖徵
+      embed_html_disabled: HTML 內嵌對此地圖圖層不可用
     changesets:
       show:
         comment: 評論
index 87c467c88301b11970ea43e365134f58f153bb0a..1c9c7e0a1123481543d2f2950b733fee71f5aeac 100644 (file)
@@ -53,6 +53,8 @@ api_timeout: 300
 web_timeout: 30
 # Periods (in hours) which are allowed for user blocks
 user_block_periods: [0, 1, 3, 6, 12, 24, 48, 96, 168, 336, 731, 4383, 8766, 87660]
+# Account deletion cooldown period (in hours) since last changeset close; null to disable, 0 to make sure there aren't any open changesets when the deletion happens
+user_account_deletion_delay: null
 # Rate limit for message sending
 max_messages_per_hour: 60
 # Rate limit for friending
diff --git a/db/migrate/20231117170422_add_closed_at_index_to_changesets.rb b/db/migrate/20231117170422_add_closed_at_index_to_changesets.rb
new file mode 100644 (file)
index 0000000..e9d7e62
--- /dev/null
@@ -0,0 +1,7 @@
+class AddClosedAtIndexToChangesets < ActiveRecord::Migration[7.1]
+  disable_ddl_transaction!
+
+  def change
+    add_index :changesets, [:user_id, :closed_at], :algorithm => :concurrently
+  end
+end
index 56e778523f7a7597d3a26670cc0dae97187a57e7..f74d4d571e2f58c8d3ef65009af3345d6128ea7b 100644 (file)
@@ -2499,6 +2499,13 @@ CREATE INDEX index_changeset_comments_on_changeset_id_and_created_at ON public.c
 CREATE INDEX index_changeset_comments_on_created_at ON public.changeset_comments USING btree (created_at);
 
 
+--
+-- Name: index_changesets_on_user_id_and_closed_at; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_changesets_on_user_id_and_closed_at ON public.changesets USING btree (user_id, closed_at);
+
+
 --
 -- Name: index_changesets_subscribers_on_changeset_id; Type: INDEX; Schema: public; Owner: -
 --
@@ -3499,6 +3506,7 @@ INSERT INTO "schema_migrations" (version) VALUES
 ('23'),
 ('22'),
 ('21'),
+('20231117170422'),
 ('20231101222146'),
 ('20231029151516'),
 ('20231010194809'),
index 7734ce996f7f095dffc871c2b01d80cfc9aa3ce8..8ddc54561c52b93b7110fc75681b471810f8ac1d 100644 (file)
@@ -9,11 +9,11 @@ class GuestApiAbilityTest < ApiAbilityTest
   test "note permissions for a guest" do
     ability = ApiAbility.new nil
 
-    [:index, :create, :comment, :feed, :show, :search].each do |action|
+    [:index, :create, :feed, :show, :search].each do |action|
       assert ability.can?(action, Note), "should be able to #{action} Notes"
     end
 
-    [:close, :reopen, :destroy].each do |action|
+    [:comment, :close, :reopen, :destroy].each do |action|
       assert ability.cannot?(action, Note), "should not be able to #{action} Notes"
     end
   end
index 7546c3797ee6f2939834dd1d9a0fc1b68587f6ba..131292f412d90f286b8798b81b84bde1015b2be4 100644 (file)
@@ -152,4 +152,23 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest
     # Make sure we have a button to "go public"
     assert_select "form.button_to[action='/user/go_public']", true
   end
+
+  def test_destroy_allowed
+    user = create(:user)
+    session_for(user)
+
+    delete account_path
+    assert_response :redirect
+  end
+
+  def test_destroy_not_allowed
+    with_user_account_deletion_delay(24) do
+      user = create(:user)
+      create(:changeset, :user => user, :created_at => Time.now.utc)
+      session_for(user)
+
+      delete account_path
+      assert_response :bad_request
+    end
+  end
 end
index 19bc7980828ea5f5cb785686b83cda3d89721574..43fbe4df495a3db150889ccdd0215e884c1bc865 100644 (file)
@@ -77,7 +77,7 @@ class Oauth2AuthorizationsControllerTest < ActionDispatch::IntegrationTest
                                  :redirect_uri => "https://bad.example.com/",
                                  :response_type => "code",
                                  :scope => "write_api")
-    assert_response :success
+    assert_response :bad_request
     assert_template "oauth2_authorizations/error"
     assert_select "p", "The requested redirect uri is malformed or doesn't match client redirect URI."
   end
@@ -91,7 +91,7 @@ class Oauth2AuthorizationsControllerTest < ActionDispatch::IntegrationTest
                                  :redirect_uri => application.redirect_uri,
                                  :response_type => "code",
                                  :scope => "bad_scope")
-    assert_response :success
+    assert_response :bad_request
     assert_template "oauth2_authorizations/error"
     assert_select "p", "The requested scope is invalid, unknown, or malformed."
 
@@ -99,7 +99,7 @@ class Oauth2AuthorizationsControllerTest < ActionDispatch::IntegrationTest
                                  :redirect_uri => application.redirect_uri,
                                  :response_type => "code",
                                  :scope => "write_prefs")
-    assert_response :success
+    assert_response :bad_request
     assert_template "oauth2_authorizations/error"
     assert_select "p", "The requested scope is invalid, unknown, or malformed."
   end
index a4ed07e09eac0079a610f8e03762b0b89aeda105..5c48bb9698a6a73d56b7ab120b871d24902d18c5 100644 (file)
@@ -282,4 +282,62 @@ class UserTest < ActiveSupport::TestCase
     oauth_access_token.reload
     assert_predicate oauth_access_token, :revoked?
   end
+
+  def test_deletion_allowed_when_no_changesets
+    with_user_account_deletion_delay(10000) do
+      user = create(:user)
+      assert_predicate user, :deletion_allowed?
+    end
+  end
+
+  def test_deletion_allowed_without_delay
+    with_user_account_deletion_delay(nil) do
+      user = create(:user)
+      create(:changeset, :user => user)
+      user.reload
+      assert_predicate user, :deletion_allowed?
+    end
+  end
+
+  def test_deletion_allowed_past_delay
+    with_user_account_deletion_delay(10) do
+      user = create(:user)
+      create(:changeset, :user => user, :created_at => Time.now.utc - 12.hours, :closed_at => Time.now.utc - 10.hours)
+      user.reload
+      assert_predicate user, :deletion_allowed?
+    end
+  end
+
+  def test_deletion_allowed_during_delay
+    with_user_account_deletion_delay(10) do
+      user = create(:user)
+      create(:changeset, :user => user, :created_at => Time.now.utc - 11.hours, :closed_at => Time.now.utc - 9.hours)
+      user.reload
+      assert_not_predicate user, :deletion_allowed?
+      assert_equal Time.now.utc + 1.hour, user.deletion_allowed_at
+    end
+  end
+
+  def test_deletion_allowed_past_zero_delay
+    with_user_account_deletion_delay(0) do
+      user = create(:user)
+      create(:changeset, :user => user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour)
+      travel 90.minutes do
+        user.reload
+        assert_predicate user, :deletion_allowed?
+      end
+    end
+  end
+
+  def test_deletion_allowed_during_zero_delay
+    with_user_account_deletion_delay(0) do
+      user = create(:user)
+      create(:changeset, :user => user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour)
+      travel 30.minutes do
+        user.reload
+        assert_not_predicate user, :deletion_allowed?
+        assert_equal Time.now.utc + 30.minutes, user.deletion_allowed_at
+      end
+    end
+  end
 end
index 87e981c6426500443bcbf6811cef581f8ffce9b1..e6517dccc38b6bd0c5b17bb3463c5e34111bfdd3 100644 (file)
@@ -41,4 +41,59 @@ class AccountDeletionTest < ApplicationSystemTestCase
 
     assert_content "Account Deleted"
   end
+
+  test "can delete with any delay setting value if the user has no changesets" do
+    with_user_account_deletion_delay(10000) do
+      travel 1.hour do
+        visit edit_account_path
+
+        click_link "Delete Account..."
+
+        assert_no_content "cannot currently be deleted"
+      end
+    end
+  end
+
+  test "can delete with delay disabled" do
+    with_user_account_deletion_delay(nil) do
+      create(:changeset, :user => @user)
+
+      travel 1.hour do
+        visit edit_account_path
+
+        click_link "Delete Account..."
+
+        assert_no_content "cannot currently be deleted"
+      end
+    end
+  end
+
+  test "can delete when last changeset is old enough" do
+    with_user_account_deletion_delay(10) do
+      create(:changeset, :user => @user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour)
+
+      travel 12.hours do
+        visit edit_account_path
+
+        click_link "Delete Account..."
+
+        assert_no_content "cannot currently be deleted"
+      end
+    end
+  end
+
+  test "can't delete when last changeset isn't old enough" do
+    with_user_account_deletion_delay(10) do
+      create(:changeset, :user => @user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour)
+
+      travel 10.hours do
+        visit edit_account_path
+
+        click_link "Delete Account..."
+
+        assert_content "cannot currently be deleted"
+        assert_content "in about 1 hour"
+      end
+    end
+  end
 end
index 68749c0f70f595e00b322b21acee0215b7d46b51..19e1a2784611fa219af508a181909c7ead6f320c 100644 (file)
@@ -371,5 +371,16 @@ module ActiveSupport
         el << tag_el
       end
     end
+
+    def with_user_account_deletion_delay(value)
+      freeze_time
+      default_value = Settings.user_account_deletion_delay
+      Settings.user_account_deletion_delay = value
+
+      yield
+
+      Settings.user_account_deletion_delay = default_value
+      unfreeze_time
+    end
   end
 end
index b1d4b6451c54e0e251e54a6674e491753fac23e1..a63202522c2fa494b92c615cf16516e5807aeb7a 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/js@8.53.0":
-  version "8.53.0"
-  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
-  integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==
+"@eslint/js@8.54.0":
+  version "8.54.0"
+  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf"
+  integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==
 
 "@humanwhocodes/config-array@^0.11.13":
   version "0.11.13"
@@ -229,14 +229,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
   integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
 
 eslint@^8.0.0:
-  version "8.53.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce"
-  integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==
+  version "8.54.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537"
+  integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==
   dependencies:
     "@eslint-community/eslint-utils" "^4.2.0"
     "@eslint-community/regexpp" "^4.6.1"
     "@eslint/eslintrc" "^2.1.3"
-    "@eslint/js" "8.53.0"
+    "@eslint/js" "8.54.0"
     "@humanwhocodes/config-array" "^0.11.13"
     "@humanwhocodes/module-importer" "^1.0.1"
     "@nodelib/fs.walk" "^1.2.8"