From: Andy Allan Date: Thu, 18 Jan 2024 10:47:17 +0000 (+0000) Subject: Merge pull request #4218 from AntonKhorev/no-user-id-renames X-Git-Tag: live~1330 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/7406ae5dcc9cbb177a8ea33085af9caf6e3ebb1b?hp=0a210801928a00d02ad8b9df809650004ae60f74 Merge pull request #4218 from AntonKhorev/no-user-id-renames Disallow username changes to user_n if n isn't their id --- diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0608b699b..9fc132014 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -50,7 +50,7 @@ jobs: rubygems: 3.4.10 bundler-cache: true - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: node_modules key: yarn-${{ env.os }}-${{ hashFiles('yarn.lock') }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f2fa6763a..bfe456076 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: rubygems: 3.4.10 bundler-cache: true - name: Cache node modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: node_modules key: yarn-ubuntu-${{ matrix.ubuntu }}-${{ hashFiles('yarn.lock') }} diff --git a/.rubocop.yml b/.rubocop.yml index 97bb72e0a..ddfb63cae 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -37,9 +37,6 @@ Metrics/ClassLength: Metrics/ModuleLength: Max: 150 -Minitest/MultipleAssertions: - Enabled: false - Naming/FileName: Exclude: - 'script/deliver-message' @@ -71,6 +68,9 @@ Rails/SkipsModelValidations: - 'db/migrate/*.rb' - 'app/controllers/users_controller.rb' +Style/ArgumentsForwarding: + Enabled: false + Style/Documentation: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d80653712..9874aa379 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -14,6 +14,11 @@ require: - rubocop-rails - rubocop-rake +# Offense count: 11 +# Configuration parameters: Include, MaxAmount +FactoryBot/ExcessiveCreateList: + MaxAmount: 200 + # Offense count: 557 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. @@ -66,7 +71,7 @@ Metrics/ClassLength: # Offense count: 59 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: - Max: 26 + Max: 29 # Offense count: 753 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. @@ -81,7 +86,7 @@ Metrics/ParameterLists: # Offense count: 56 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: - Max: 29 + Max: 30 # Offense count: 2394 # This cop supports safe autocorrection (--autocorrect). diff --git a/Gemfile.lock b/Gemfile.lock index 29ad5ed31..e0ffd49be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,35 +3,36 @@ GEM specs: aasm (5.5.0) concurrent-ruby (~> 1.0) - actioncable (7.1.2) - actionpack (= 7.1.2) - activesupport (= 7.1.2) + abbrev (0.1.2) + actioncable (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.2) - actionpack (= 7.1.2) - activejob (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + actionmailbox (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.2) - actionpack (= 7.1.2) - actionview (= 7.1.2) - activejob (= 7.1.2) - activesupport (= 7.1.2) + actionmailer (7.1.3) + actionpack (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activesupport (= 7.1.3) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.2) - actionview (= 7.1.2) - activesupport (= 7.1.2) + actionpack (7.1.3) + actionview (= 7.1.3) + activesupport (= 7.1.3) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -41,39 +42,39 @@ GEM rails-html-sanitizer (~> 1.6) actionpack-page_caching (1.2.4) actionpack (>= 4.0.0) - actiontext (7.1.2) - actionpack (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + actiontext (7.1.3) + actionpack (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.2) - activesupport (= 7.1.2) + actionview (7.1.3) + activesupport (= 7.1.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_record_union (1.3.0) activerecord (>= 4.0) - activejob (7.1.2) - activesupport (= 7.1.2) + activejob (7.1.3) + activesupport (= 7.1.3) globalid (>= 0.3.6) - activemodel (7.1.2) - activesupport (= 7.1.2) - activerecord (7.1.2) - activemodel (= 7.1.2) - activesupport (= 7.1.2) + activemodel (7.1.3) + activesupport (= 7.1.3) + activerecord (7.1.3) + activemodel (= 7.1.3) + activesupport (= 7.1.3) timeout (>= 0.4.0) activerecord-import (1.5.1) activerecord (>= 4.2) - activestorage (7.1.2) - actionpack (= 7.1.2) - activejob (= 7.1.2) - activerecord (= 7.1.2) - activesupport (= 7.1.2) + activestorage (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activesupport (= 7.1.3) marcel (~> 1.0) - activesupport (7.1.2) + activesupport (7.1.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -95,16 +96,16 @@ GEM autoprefixer-rails (10.4.16.0) execjs (~> 2) aws-eventstream (1.3.0) - aws-partitions (1.869.0) - aws-sdk-core (3.190.0) + aws-partitions (1.880.0) + aws-sdk-core (3.190.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.75.0) + aws-sdk-kms (1.76.0) aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.141.0) + aws-sdk-s3 (1.142.0) aws-sdk-core (~> 3, >= 3.189.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -125,7 +126,7 @@ GEM bigdecimal (3.1.5) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bootsnap (1.17.0) + bootsnap (1.17.1) msgpack (~> 1.2) bootstrap (5.3.2) autoprefixer-rails (>= 9.1.0) @@ -133,7 +134,8 @@ GEM bootstrap_form (5.4.0) actionpack (>= 6.1) activemodel (>= 6.1) - brakeman (6.1.0) + brakeman (6.1.1) + racc brotli (0.4.0) browser (5.3.1) builder (3.2.4) @@ -151,7 +153,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) config (5.1.0) deep_merge (~> 1.2, >= 1.2.1) dry-validation (~> 1.0, >= 1.0.0) @@ -206,7 +208,8 @@ GEM dry-logic (>= 1.4, < 2) dry-types (>= 1.7, < 2) zeitwerk (~> 2.6) - dry-types (1.7.1) + dry-types (1.7.2) + bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) @@ -228,16 +231,15 @@ GEM erubi (1.12.0) execjs (2.9.1) exifr (1.4.0) - factory_bot (6.4.2) + factory_bot (6.4.5) activesupport (>= 5.0.0) - factory_bot_rails (6.4.2) + factory_bot_rails (6.4.3) factory_bot (~> 6.4) railties (>= 5.0.0) - faraday (2.7.12) - base64 - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) + faraday (2.9.0) + faraday-net_http (>= 2.0, < 3.2) + faraday-net_http (3.1.0) + net-http ffi (1.16.3) ffi-compiler (1.0.1) ffi (>= 1.0.0) @@ -252,10 +254,11 @@ GEM ffi (>= 1.0.0) globalid (1.2.1) activesupport (>= 6.1) - google-protobuf (3.25.1) + google-protobuf (3.25.2) hashdiff (1.1.0) hashie (5.0.0) - highline (2.1.0) + highline (3.0.0) + abbrev htmlentities (4.3.4) http_accept_language (2.1.1) i18n (1.14.1) @@ -286,12 +289,12 @@ GEM image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) - image_size (3.3.0) + image_size (3.4.0) in_threads (1.6.0) io-console (0.7.1) - irb (1.10.1) + irb (1.11.1) rdoc - reline (>= 0.3.8) + reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) @@ -307,7 +310,7 @@ GEM rexml language_server-protocol (3.17.0.3) libv8-node (18.16.0.0) - libxml-ruby (4.1.2) + libxml-ruby (5.0.2) listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -330,22 +333,24 @@ GEM mini_portile2 (2.8.5) mini_racer (0.8.0) libv8-node (~> 18.16.0.0) - minitest (5.20.0) + minitest (5.21.1) msgpack (1.7.2) multi_json (1.15.0) multi_xml (0.6.0) mutex_m (0.2.0) - net-imap (0.4.8) + net-http (0.4.1) + uri + net-imap (0.4.9.1) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.4.0) + net-smtp (0.4.0.1) net-protocol nio4r (2.7.0) - nokogiri (1.15.5) + nokogiri (1.16.0) mini_portile2 (~> 2.8.2) racc (~> 1.4) oauth (0.4.7) @@ -378,7 +383,8 @@ GEM omniauth-mediawiki (0.0.4) jwt (~> 2.0) omniauth-oauth (~> 1.0) - omniauth-microsoft_graph (1.2.0) + omniauth-microsoft_graph (2.0.0) + jwt (~> 2.0) omniauth (~> 2.0) omniauth-oauth2 (~> 1.8.0) omniauth-oauth (1.2.0) @@ -395,7 +401,7 @@ GEM omniauth (~> 2.0) openstreetmap-deadlock_retry (1.3.1) parallel (1.24.0) - parser (3.2.2.4) + parser (3.3.0.4) ast (~> 2.4.1) racc pg (1.5.4) @@ -404,7 +410,7 @@ GEM psych (5.1.2) stringio public_suffix (5.0.4) - puma (5.6.7) + puma (5.6.8) nio4r (~> 2.0) quad_tile (1.0.1) racc (1.7.3) @@ -414,7 +420,8 @@ GEM rack-openid (1.4.2) rack (>= 1.1.0) ruby-openid (>= 2.1.8) - rack-protection (3.1.0) + rack-protection (3.2.0) + base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) rack-session (1.0.2) rack (< 3) @@ -424,20 +431,20 @@ GEM rackup (1.0.0) rack (< 3) webrick - rails (7.1.2) - actioncable (= 7.1.2) - actionmailbox (= 7.1.2) - actionmailer (= 7.1.2) - actionpack (= 7.1.2) - actiontext (= 7.1.2) - actionview (= 7.1.2) - activejob (= 7.1.2) - activemodel (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + rails (7.1.3) + actioncable (= 7.1.3) + actionmailbox (= 7.1.3) + actionmailer (= 7.1.3) + actionpack (= 7.1.3) + actiontext (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activemodel (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) bundler (>= 1.15.0) - railties (= 7.1.2) + railties (= 7.1.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -452,9 +459,9 @@ GEM rails-i18n (7.0.8) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.1.2) - actionpack (= 7.1.2) - activesupport (= 7.1.2) + railties (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -467,8 +474,8 @@ GEM ffi (~> 1.0) rdoc (6.6.2) psych (>= 4.0.0) - regexp_parser (2.8.3) - reline (0.4.1) + regexp_parser (2.9.0) + reline (0.4.2) io-console (~> 0.5) request_store (1.5.1) rack (>= 1.4) @@ -478,11 +485,11 @@ GEM rouge (4.2.0) rtlcss (0.2.1) mini_racer (>= 0.6.3) - rubocop (1.59.0) + rubocop (1.60.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.2.4) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) @@ -491,17 +498,17 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.30.0) parser (>= 3.2.1.0) - rubocop-capybara (2.19.0) + rubocop-capybara (2.20.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.25.1) rubocop (~> 1.41) - rubocop-factory_bot (2.24.0) - rubocop (~> 1.33) - rubocop-minitest (0.34.1) + rubocop-minitest (0.34.4) rubocop (>= 1.39, < 2.0) rubocop-ast (>= 1.30.0, < 2.0) - rubocop-performance (1.20.0) + rubocop-performance (1.20.2) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.30.0, < 2.0) - rubocop-rails (2.23.0) + rubocop-rails (2.23.1) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) @@ -547,7 +554,7 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) stringio (3.1.0) - strong_migrations (1.6.4) + strong_migrations (1.7.0) activerecord (>= 5.2) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -559,6 +566,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) + uri (0.13.0) validates_email_format_of (1.7.2) i18n vendorer (0.2.0) diff --git a/INSTALL.md b/INSTALL.md index ec219b504..63aad6f1a 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,7 +23,7 @@ of packages required before you can get the various gems installed. ## Minimum requirements * Ruby 3.0+ -* PostgreSQL 12+ +* PostgreSQL 13+ * Bundler (see note below about [developer Ruby setup](#rbenv)) * Javascript Runtime @@ -226,11 +226,11 @@ After installing this software, you may need to carry out some [configuration st # Ruby development install and versions (optional) -For simplicity, this document explains how to install all the website dependencies as "system" dependencies. While this is simpler, and usually faster, you might want more control over the process or the ability to install multiple different versions of software alongside eachother. For many developers, [`rbenv`](https://github.com/rbenv/rbenv) is the easiest way to manage multiple different Ruby versions on the same computer - with the added advantage that the installs are all in your home directory, so you don't need administrator permissions. +For simplicity, this document explains how to install all the website dependencies as "system" dependencies. While this is simpler, and usually faster, you might want more control over the process or the ability to install multiple different versions of software alongside each other. For many developers, [`rbenv`](https://github.com/rbenv/rbenv) is the easiest way to manage multiple different Ruby versions on the same computer - with the added advantage that the installs are all in your home directory, so you don't need administrator permissions. If you choose to install Ruby and Bundler via `rbenv`, then you do not need to install the system libraries for Ruby: -* For Ubuntu, you do not need to install the following packages: `ruby3.0 libruby3.0 ruby3.0-dev bundler`, +* For Ubuntu, you do not need to install the following packages: `ruby ruby-dev ruby-bundler`, * For Fedora, you do not need to install the following packages: `ruby ruby-devel rubygem-rdoc rubygem-bundler rubygems` * For MacOSX, you do not need to `brew install ruby` - but make sure you've installed a version of Ruby using `rbenv` before running `gem install bundler`! diff --git a/app/abilities/ability.rb b/app/abilities/ability.rb index b9da5d08a..c7080595c 100644 --- a/app/abilities/ability.rb +++ b/app/abilities/ability.rb @@ -25,12 +25,6 @@ class Ability can [:index, :show, :data, :georss, :picture, :icon], Trace can [:terms, :new, :create, :save, :suspended, :show, :auth_success, :auth_failure], User can [:index, :show, :blocks_on, :blocks_by], UserBlock - can [:index, :show], Node - can [:index, :show, :full, :ways_for_node], Way - can [:index, :show, :full, :relations_for_node, :relations_for_way, :relations_for_relation], Relation - can [:history, :version], OldNode - can [:history, :version], OldWay - can [:history, :version], OldRelation end if user&.active? @@ -61,7 +55,7 @@ class Ability can [:index, :show, :resolve, :ignore, :reopen], Issue can :create, IssueComment can [:new, :create, :edit, :update, :destroy], Redaction - can [:new, :edit, :create, :update, :revoke], UserBlock + can [:new, :edit, :create, :update, :revoke, :revoke_all], UserBlock end if user.administrator? diff --git a/app/abilities/api_ability.rb b/app/abilities/api_ability.rb index 4876380d0..0eae46f82 100644 --- a/app/abilities/api_ability.rb +++ b/app/abilities/api_ability.rb @@ -5,7 +5,6 @@ class ApiAbility def initialize(user) can :show, :capability - can :index, :change can :index, :map can :show, :permission can :show, :version @@ -22,17 +21,9 @@ class ApiAbility can [:history, :version], OldWay can [:history, :version], OldRelation can [:show], UserBlock - end - - if user&.active? - can :welcome, :site - can [:revoke, :authorize], :oauth - if Settings.status != "database_offline" - can [:index, :new, :create, :show, :edit, :update, :destroy], ClientApplication - can [:new, :create, :reply, :show, :inbox, :outbox, :mark, :destroy], Message + if user&.active? can [:comment, :close, :reopen], Note - can [:new, :create], Report can [:create, :show, :update, :destroy, :data], Trace can [:details, :gpx_files], User can [:index, :show, :update, :update_all, :destroy], UserPreference diff --git a/app/abilities/api_capability.rb b/app/abilities/api_capability.rb index 8c52327cf..95d7ab9ab 100644 --- a/app/abilities/api_capability.rb +++ b/app/abilities/api_capability.rb @@ -32,9 +32,9 @@ class ApiCapability can [:destroy, :restore], ChangesetComment if scope?(token, :write_api) can :destroy, Note if scope?(token, :write_notes) if user&.terms_agreed? - can :redact, OldNode if scope?(token, :write_api) - can :redact, OldWay if scope?(token, :write_api) - can :redact, OldRelation if scope?(token, :write_api) + can :redact, OldNode if scope?(token, :write_api) || scope?(token, :write_redactions) + can :redact, OldWay if scope?(token, :write_api) || scope?(token, :write_redactions) + can :redact, OldRelation if scope?(token, :write_api) || scope?(token, :write_redactions) end end end diff --git a/app/assets/images/key/cyclemap/beach.png b/app/assets/images/key/cyclemap/beach.png new file mode 100644 index 000000000..256732b6e Binary files /dev/null and b/app/assets/images/key/cyclemap/beach.png differ diff --git a/app/assets/images/key/cyclemap/bicycle_parking.png b/app/assets/images/key/cyclemap/bicycle_parking.png index c900a4495..e5a781d13 100644 Binary files a/app/assets/images/key/cyclemap/bicycle_parking.png and b/app/assets/images/key/cyclemap/bicycle_parking.png differ diff --git a/app/assets/images/key/cyclemap/bicycle_parking_small.svg b/app/assets/images/key/cyclemap/bicycle_parking_small.svg new file mode 100644 index 000000000..753fab746 --- /dev/null +++ b/app/assets/images/key/cyclemap/bicycle_parking_small.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/key/cyclemap/bicycle_rental.png b/app/assets/images/key/cyclemap/bicycle_rental.png new file mode 100644 index 000000000..190e52755 Binary files /dev/null and b/app/assets/images/key/cyclemap/bicycle_rental.png differ diff --git a/app/assets/images/key/cyclemap/bicycle_rental_small.svg b/app/assets/images/key/cyclemap/bicycle_rental_small.svg new file mode 100644 index 000000000..fa0399c16 --- /dev/null +++ b/app/assets/images/key/cyclemap/bicycle_rental_small.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/key/cyclemap/cycleway.png b/app/assets/images/key/cyclemap/cycleway.png deleted file mode 100644 index 13bed4a7d..000000000 Binary files a/app/assets/images/key/cyclemap/cycleway.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/footway.svg b/app/assets/images/key/cyclemap/footway.svg deleted file mode 100644 index ecad17425..000000000 --- a/app/assets/images/key/cyclemap/footway.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/cyclemap/motorway12.png b/app/assets/images/key/cyclemap/motorway12.png deleted file mode 100644 index 749493ad6..000000000 Binary files a/app/assets/images/key/cyclemap/motorway12.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/pedestrian.svg b/app/assets/images/key/cyclemap/pedestrian.svg deleted file mode 100644 index af8fce170..000000000 --- a/app/assets/images/key/cyclemap/pedestrian.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/cyclemap/primary12.png b/app/assets/images/key/cyclemap/primary12.png deleted file mode 100644 index fed37d054..000000000 Binary files a/app/assets/images/key/cyclemap/primary12.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/rail.png b/app/assets/images/key/cyclemap/rail.png deleted file mode 100644 index 0abf0c1df..000000000 Binary files a/app/assets/images/key/cyclemap/rail.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/rail14.png b/app/assets/images/key/cyclemap/rail14.png deleted file mode 100644 index 957f17c85..000000000 Binary files a/app/assets/images/key/cyclemap/rail14.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/secondary12.png b/app/assets/images/key/cyclemap/secondary12.png deleted file mode 100644 index cde008523..000000000 Binary files a/app/assets/images/key/cyclemap/secondary12.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/track.png b/app/assets/images/key/cyclemap/track.png deleted file mode 100644 index f294edca0..000000000 Binary files a/app/assets/images/key/cyclemap/track.png and /dev/null differ diff --git a/app/assets/images/key/cyclemap/trunk12.png b/app/assets/images/key/cyclemap/trunk12.png deleted file mode 100644 index 51230a021..000000000 Binary files a/app/assets/images/key/cyclemap/trunk12.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/bridge.svg b/app/assets/images/key/mapnik/bridge.svg deleted file mode 100644 index 4096e8166..000000000 --- a/app/assets/images/key/mapnik/bridge.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/mapnik/bridleway.png b/app/assets/images/key/mapnik/bridleway.png deleted file mode 100644 index 9aec1ad33..000000000 Binary files a/app/assets/images/key/mapnik/bridleway.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/building15.svg b/app/assets/images/key/mapnik/building15.svg deleted file mode 100644 index cc0507340..000000000 --- a/app/assets/images/key/mapnik/building15.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/mapnik/building16.svg b/app/assets/images/key/mapnik/building16.svg deleted file mode 100644 index 6ff2210a5..000000000 --- a/app/assets/images/key/mapnik/building16.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/mapnik/capital4.svg b/app/assets/images/key/mapnik/capital4.svg new file mode 100644 index 000000000..712c904d0 --- /dev/null +++ b/app/assets/images/key/mapnik/capital4.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/images/key/mapnik/capital7.svg b/app/assets/images/key/mapnik/capital7.svg new file mode 100644 index 000000000..69011cfa9 --- /dev/null +++ b/app/assets/images/key/mapnik/capital7.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/images/key/mapnik/city4.svg b/app/assets/images/key/mapnik/city4.svg new file mode 100644 index 000000000..542236cad --- /dev/null +++ b/app/assets/images/key/mapnik/city4.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/key/mapnik/city6.svg b/app/assets/images/key/mapnik/city6.svg new file mode 100644 index 000000000..40fc3aebc --- /dev/null +++ b/app/assets/images/key/mapnik/city6.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/images/key/mapnik/cycleway.png b/app/assets/images/key/mapnik/cycleway.png deleted file mode 100644 index a1a16f1ed..000000000 Binary files a/app/assets/images/key/mapnik/cycleway.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/footway.png b/app/assets/images/key/mapnik/footway.png deleted file mode 100644 index 4486119ba..000000000 Binary files a/app/assets/images/key/mapnik/footway.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/glacier10.svg b/app/assets/images/key/mapnik/glacier10.svg deleted file mode 100644 index be79f238a..000000000 --- a/app/assets/images/key/mapnik/glacier10.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/mapnik/glacier5.svg b/app/assets/images/key/mapnik/glacier5.svg deleted file mode 100644 index 8e6d368eb..000000000 --- a/app/assets/images/key/mapnik/glacier5.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/mapnik/mainroad.png b/app/assets/images/key/mapnik/mainroad.png deleted file mode 100644 index 269959b65..000000000 Binary files a/app/assets/images/key/mapnik/mainroad.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/mainroad12.png b/app/assets/images/key/mapnik/mainroad12.png deleted file mode 100644 index c289a3f8c..000000000 Binary files a/app/assets/images/key/mapnik/mainroad12.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/mainroad12.svg b/app/assets/images/key/mapnik/mainroad12.svg new file mode 100644 index 000000000..6bf11d915 --- /dev/null +++ b/app/assets/images/key/mapnik/mainroad12.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/images/key/mapnik/mainroad15.svg b/app/assets/images/key/mapnik/mainroad15.svg new file mode 100644 index 000000000..96796b86e --- /dev/null +++ b/app/assets/images/key/mapnik/mainroad15.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/images/key/mapnik/mainroad8.png b/app/assets/images/key/mapnik/mainroad8.png deleted file mode 100644 index 05b4dac85..000000000 Binary files a/app/assets/images/key/mapnik/mainroad8.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/mainroad8.svg b/app/assets/images/key/mapnik/mainroad8.svg new file mode 100644 index 000000000..ab5ab3f64 --- /dev/null +++ b/app/assets/images/key/mapnik/mainroad8.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/images/key/mapnik/mainroad9.svg b/app/assets/images/key/mapnik/mainroad9.svg new file mode 100644 index 000000000..75195d9fb --- /dev/null +++ b/app/assets/images/key/mapnik/mainroad9.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/images/key/mapnik/motorway.png b/app/assets/images/key/mapnik/motorway.png deleted file mode 100644 index 484fc9daa..000000000 Binary files a/app/assets/images/key/mapnik/motorway.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/rail12.svg b/app/assets/images/key/mapnik/rail12.svg deleted file mode 100644 index 45c76a41e..000000000 --- a/app/assets/images/key/mapnik/rail12.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/mapnik/rail18.svg b/app/assets/images/key/mapnik/rail18.svg deleted file mode 100644 index 5094bafde..000000000 --- a/app/assets/images/key/mapnik/rail18.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/mapnik/track.png b/app/assets/images/key/mapnik/track.png deleted file mode 100644 index f294edca0..000000000 Binary files a/app/assets/images/key/mapnik/track.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/tram15.svg b/app/assets/images/key/mapnik/tram15.svg deleted file mode 100644 index 8f873f7ee..000000000 --- a/app/assets/images/key/mapnik/tram15.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/mapnik/tunnel.svg b/app/assets/images/key/mapnik/tunnel.svg deleted file mode 100644 index 05cd7e713..000000000 --- a/app/assets/images/key/mapnik/tunnel.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/mapnik/unclassified.png b/app/assets/images/key/mapnik/unclassified.png deleted file mode 100644 index 3cdfb2dda..000000000 Binary files a/app/assets/images/key/mapnik/unclassified.png and /dev/null differ diff --git a/app/assets/images/key/mapnik/unclassified13.png b/app/assets/images/key/mapnik/unclassified13.png deleted file mode 100644 index 1a8792462..000000000 Binary files a/app/assets/images/key/mapnik/unclassified13.png and /dev/null differ diff --git a/app/assets/images/key/opnvkarte/main_road11.svg b/app/assets/images/key/opnvkarte/main_road11.svg deleted file mode 100644 index b03c74414..000000000 --- a/app/assets/images/key/opnvkarte/main_road11.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/main_road13.svg b/app/assets/images/key/opnvkarte/main_road13.svg deleted file mode 100644 index 2d5902236..000000000 --- a/app/assets/images/key/opnvkarte/main_road13.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/main_road15.svg b/app/assets/images/key/opnvkarte/main_road15.svg deleted file mode 100644 index cb5391648..000000000 --- a/app/assets/images/key/opnvkarte/main_road15.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/main_road17.svg b/app/assets/images/key/opnvkarte/main_road17.svg deleted file mode 100644 index de7db0f17..000000000 --- a/app/assets/images/key/opnvkarte/main_road17.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/motorway13.svg b/app/assets/images/key/opnvkarte/motorway13.svg deleted file mode 100644 index c44e777a2..000000000 --- a/app/assets/images/key/opnvkarte/motorway13.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/motorway15.svg b/app/assets/images/key/opnvkarte/motorway15.svg deleted file mode 100644 index c217bb2a7..000000000 --- a/app/assets/images/key/opnvkarte/motorway15.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/opnvkarte/motorway17.svg b/app/assets/images/key/opnvkarte/motorway17.svg deleted file mode 100644 index 36b37db59..000000000 --- a/app/assets/images/key/opnvkarte/motorway17.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/opnvkarte/motorway8.svg b/app/assets/images/key/opnvkarte/motorway8.svg deleted file mode 100644 index 21f006cef..000000000 --- a/app/assets/images/key/opnvkarte/motorway8.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/assets/images/key/opnvkarte/rail11.svg b/app/assets/images/key/opnvkarte/rail11.svg deleted file mode 100644 index 849f5cf94..000000000 --- a/app/assets/images/key/opnvkarte/rail11.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/key/opnvkarte/rail15.svg b/app/assets/images/key/opnvkarte/rail15.svg deleted file mode 100644 index efe7792b9..000000000 --- a/app/assets/images/key/opnvkarte/rail15.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/assets/images/sprite.svg b/app/assets/images/sprite.svg index 382bc41fd..ae2e03c6b 100644 --- a/app/assets/images/sprite.svg +++ b/app/assets/images/sprite.svg @@ -1,68 +1,62 @@ - - - - - - - - - ? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + ? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index e45d28321..706647ef5 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -346,10 +346,6 @@ $(document).ready(function () { }); } }); - - $(".colour-preview-box").each(function () { - $(this).css("background-color", $(this).data("colour")); - }); } page.unload = function () { diff --git a/app/assets/javascripts/index/note.js b/app/assets/javascripts/index/note.js index e7790c904..15fedb1d1 100644 --- a/app/assets/javascripts/index/note.js +++ b/app/assets/javascripts/index/note.js @@ -52,20 +52,18 @@ OSM.Note = function (map) { OSM.loadSidebarContent(path, function () { initialize(path, id, moveToNote); }); + }, + error: function (xhr) { + $(form).find("#comment-error") + .text(xhr.responseText) + .prop("hidden", false); + updateButtons(form); } }); }); content.find("textarea").on("input", function (e) { - var form = e.target.form; - - if ($(e.target).val() === "") { - $(form.close).val($(form.close).data("defaultActionText")); - $(form.comment).prop("disabled", true); - } else { - $(form.close).val($(form.close).data("commentActionText")); - $(form.comment).prop("disabled", false); - } + updateButtons(e.target.form); }); content.find("textarea").val("").trigger("input"); @@ -84,6 +82,17 @@ OSM.Note = function (map) { if (callback) callback(); } + function updateButtons(form) { + $(form).find("input[type=submit]").prop("disabled", false); + if ($(form.text).val() === "") { + $(form.close).val($(form.close).data("defaultActionText")); + $(form.comment).prop("disabled", true); + } else { + $(form.close).val($(form.close).data("commentActionText")); + $(form.comment).prop("disabled", false); + } + } + function moveToNote() { var data = $(".details").data(); if (!data) return; diff --git a/app/assets/javascripts/messages.js b/app/assets/javascripts/messages.js index 5accc1a60..cc86da05e 100644 --- a/app/assets/javascripts/messages.js +++ b/app/assets/javascripts/messages.js @@ -22,6 +22,8 @@ $(document).ready(function () { $(".user-button").before(data.inboxanchor); $("#inbox-count").replaceWith(data.inbox_count); + $("#outbox-count").replaceWith(data.outbox_count); + $("#muted-count").replaceWith(data.muted_count); } function updateReadState(target, isRead) { diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index d598d10e3..f0746117d 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -645,12 +645,6 @@ tr.turn:hover { tr:last-child th, tr:last-child td { border-bottom: 0; } - - .colour-preview-box { - width: 14px; - height: 14px; - // add color via inline css on element: background-color: ; - } } span.action-button:hover { diff --git a/app/controllers/diary_entries_controller.rb b/app/controllers/diary_entries_controller.rb index 6db32797a..1f9574b9c 100644 --- a/app/controllers/diary_entries_controller.rb +++ b/app/controllers/diary_entries_controller.rb @@ -47,6 +47,8 @@ class DiaryEntriesController < ApplicationController @title = t ".in_language_title", :language => Language.find(params[:language]).english_name entries = entries.where(:language_code => params[:language]) else + candidate_codes = preferred_languages.flat_map(&:candidates).uniq.map(&:to_s) + @languages = Language.where(:code => candidate_codes).in_order_of(:code, candidate_codes) @title = t ".title" end end diff --git a/app/controllers/site_controller.rb b/app/controllers/site_controller.rb index 862148b92..3d830c63f 100644 --- a/app/controllers/site_controller.rb +++ b/app/controllers/site_controller.rb @@ -50,6 +50,9 @@ class SiteController < ApplicationController expires_in 7.days, :public => true @key = YAML.load_file(Rails.root.join("config/key.yml")) @key.each_value do |layer_data| + layer_data.each do |entry| + entry["name"] = Array(entry["name"]) + end layer_data.each_cons(2) do |entry, next_entry| entry["max_zoom"] = next_entry["min_zoom"] - 1 if entry["name"] == next_entry["name"] && !entry["max_zoom"] && next_entry["min_zoom"] end diff --git a/app/controllers/user_blocks_controller.rb b/app/controllers/user_blocks_controller.rb index 546c8233c..07d0bc43c 100644 --- a/app/controllers/user_blocks_controller.rb +++ b/app/controllers/user_blocks_controller.rb @@ -8,11 +8,11 @@ class UserBlocksController < ApplicationController authorize_resource - before_action :lookup_user, :only => [:new, :create, :blocks_on, :blocks_by] + before_action :lookup_user, :only => [:new, :create, :revoke_all, :blocks_on, :blocks_by] before_action :lookup_user_block, :only => [:show, :edit, :update, :revoke] before_action :require_valid_params, :only => [:create, :update] before_action :check_database_readable - before_action :check_database_writable, :only => [:create, :update, :revoke] + before_action :check_database_writable, :only => [:create, :update, :revoke, :revoke_all] def index @params = params.permit @@ -39,11 +39,13 @@ class UserBlocksController < ApplicationController def create if @valid_params + now = Time.now.utc @user_block = UserBlock.new( :user => @user, :creator => current_user, :reason => params[:user_block][:reason], - :ends_at => Time.now.utc + @block_period.hours, + :created_at => now, + :ends_at => now + @block_period.hours, :needs_view => params[:user_block][:needs_view] ) @@ -87,6 +89,16 @@ class UserBlocksController < ApplicationController end end + ## + # revokes all active blocks + def revoke_all + if request.post? && params[:confirm] + @user.blocks.active.each { |block| block.revoke!(current_user) } + flash[:notice] = t ".flash" + redirect_to user_blocks_on_path(@user) + end + end + ## # shows a list of all the blocks on the given user def blocks_on diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 961be4024..ab13f93be 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -104,11 +104,11 @@ class UsersController < ApplicationController render :action => "new" elsif current_user.auth_provider.present? # Verify external authenticator before moving on - session[:new_user] = current_user.attributes.slice("email", "display_name", "pass_crypt") + session[:new_user] = current_user.slice("email", "display_name", "pass_crypt", "pass_crypt_confirmation") redirect_to auth_url(current_user.auth_provider, current_user.auth_uid), :status => :temporary_redirect else # Save the user record - session[:new_user] = current_user.attributes.slice("email", "display_name", "pass_crypt") + session[:new_user] = current_user.slice("email", "display_name", "pass_crypt", "pass_crypt_confirmation") redirect_to :action => :terms end end diff --git a/app/helpers/authorization_helper.rb b/app/helpers/authorization_helper.rb new file mode 100644 index 000000000..11c8c298f --- /dev/null +++ b/app/helpers/authorization_helper.rb @@ -0,0 +1,13 @@ +module AuthorizationHelper + include ActionView::Helpers::TranslationHelper + + def authorization_scope(scope) + html = [] + html << t("oauth.scopes.#{scope}") + if Oauth::MODERATOR_SCOPES.include? scope + html << " " + html << image_tag("roles/moderator.png", :srcset => image_path("roles/moderator.svg", :class => "align-text-bottom"), :size => "20x20") + end + safe_join(html) + end +end diff --git a/app/helpers/browse_tags_helper.rb b/app/helpers/browse_tags_helper.rb index 1bda7dcb7..04d9a6c20 100644 --- a/app/helpers/browse_tags_helper.rb +++ b/app/helpers/browse_tags_helper.rb @@ -34,7 +34,11 @@ module BrowseTagsHelper end safe_join(phones, "; ") elsif colour_value = colour_preview(key, value) - tag.span("", :class => "colour-preview-box float-end m-1 border border-dark border-opacity-10", :"data-colour" => colour_value, :title => t("browse.tag_details.colour_preview", :colour_value => colour_value)) + colour_value + svg = tag.svg :width => 14, :height => 14, :class => "float-end m-1" do + concat tag.title t("browse.tag_details.colour_preview", :colour_value => colour_value) + concat tag.rect :x => 0.5, :y => 0.5, :width => 13, :height => 13, :fill => colour_value, :stroke => "#2222" + end + svg + colour_value else safe_join(value.split(";", -1).map { |x| linkify(h(x)) }, ";") end diff --git a/app/helpers/svg_helper.rb b/app/helpers/svg_helper.rb index abb512f0d..a40fa7086 100644 --- a/app/helpers/svg_helper.rb +++ b/app/helpers/svg_helper.rb @@ -1,7 +1,37 @@ module SvgHelper - def solid_svg_tag(width, height, fill, **options) - tag.svg :width => width, :height => height, **options do - tag.rect :width => "100%", :height => "100%", :fill => fill + def key_svg_tag(**options) + border_width = options["border"] ? (options["border-width"] || 1) : 0 + rect_attrs = { + :width => "100%", + :height => "100%", + :fill => options["fill"] || "none" + } + if border_width.positive? + rect_attrs[:x] = rect_attrs[:y] = format("%g", 0.5 * border_width) + rect_attrs[:width] = options["width"] - border_width + rect_attrs[:height] = options["height"] - border_width end + svg_attrs = options.slice("width", "height", "opacity", :class) + + tag.svg(**svg_attrs) do + horizontal = "H#{options['width']}" + concat tag.rect(**rect_attrs, **stroke_attrs(options, "border")) if options["fill"] || options["border"] + if options["line"] + y_middle = format("%g", 0.5 * options["height"]) + concat tag.path(:d => "M0,#{y_middle} #{horizontal}", **stroke_attrs(options, "line")) + end + if options["casing"] + casing_width = options["casing-width"] || 1 + y_top = format("%g", 0.5 * casing_width) + y_bottom = format("%g", options["height"] - (0.5 * casing_width)) + concat tag.path(:d => "M0,#{y_top} #{horizontal} M0,#{y_bottom} #{horizontal}", **stroke_attrs(options, "casing")) + end + end + end + + private + + def stroke_attrs(attrs, prefix) + attrs.select { |key| key.start_with?(prefix) }.transform_keys { |key| key.delete_prefix(prefix).prepend("stroke") } end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 8ca186aad..d1ad60b2c 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -44,11 +44,13 @@ class UserMailer < ApplicationMailer def gpx_success(trace, possible_points) with_recipient_locale trace.user do @to_user = trace.user.display_name + @trace_url = show_trace_url(trace.user, trace) @trace_name = trace.name @trace_points = trace.size @trace_description = trace.description @trace_tags = trace.tags @possible_points = possible_points + @my_traces_url = url_for(:controller => "traces", :action => "mine") mail :to => trace.user.email, :subject => t(".subject") diff --git a/app/models/language.rb b/app/models/language.rb index 8d3e4583f..f1d40feea 100644 --- a/app/models/language.rb +++ b/app/models/language.rb @@ -26,7 +26,7 @@ class Language < ApplicationRecord def name name = english_name - name += " (#{native_name})" unless native_name.nil? + name += " (#{native_name})" unless native_name.nil? || native_name == english_name name end end diff --git a/app/models/user.rb b/app/models/user.rb index d0993f7ee..7ca7b7a3b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -34,12 +34,13 @@ # # Indexes # -# users_auth_idx (auth_provider,auth_uid) UNIQUE -# users_display_name_idx (display_name) UNIQUE -# users_display_name_lower_idx (lower((display_name)::text)) -# users_email_idx (email) UNIQUE -# users_email_lower_idx (lower((email)::text)) -# users_home_idx (home_tile) +# users_auth_idx (auth_provider,auth_uid) UNIQUE +# users_display_name_canonical_idx (lower(NORMALIZE(display_name, NFKC))) +# users_display_name_idx (display_name) UNIQUE +# users_display_name_lower_idx (lower((display_name)::text)) +# users_email_idx (email) UNIQUE +# users_email_lower_idx (lower((email)::text)) +# users_home_idx (home_tile) # class User < ApplicationRecord @@ -95,7 +96,7 @@ class User < ApplicationRecord validates :display_name, :presence => true, :length => 3..255, :exclusion => %w[new terms save confirm confirm-email go_public reset-password forgot-password suspended] validates :display_name, :if => proc { |u| u.display_name_changed? }, - :uniqueness => { :case_sensitive => false } + :normalized_uniqueness => { :case_sensitive => false } validates :display_name, :if => proc { |u| u.display_name_changed? }, :characters => { :url_safe => true }, :whitespace => { :leading => false, :trailing => false } @@ -120,7 +121,6 @@ class User < ApplicationRecord alias_attribute :created_at, :creation_time - after_initialize :encrypt_password before_save :encrypt_password before_save :update_tile after_save :spam_check @@ -140,7 +140,7 @@ class User < ApplicationRecord user = find_by("email = ? OR display_name = ?", options[:username].strip, options[:username]) if user.nil? - users = where("LOWER(email) = LOWER(?) OR LOWER(display_name) = LOWER(?)", options[:username].strip, options[:username]) + users = where("LOWER(email) = LOWER(?) OR LOWER(NORMALIZE(display_name, NFKC)) = LOWER(NORMALIZE(?, NFKC))", options[:username].strip, options[:username]) user = users.first if users.count == 1 end diff --git a/app/validators/normalized_uniqueness_validator.rb b/app/validators/normalized_uniqueness_validator.rb new file mode 100644 index 000000000..eb3600c7b --- /dev/null +++ b/app/validators/normalized_uniqueness_validator.rb @@ -0,0 +1,18 @@ +class NormalizedUniquenessValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + relation = if options.fetch(:case_sensitive, true) + record.class.where("NORMALIZE(#{attribute}, NFKC) = NORMALIZE(?, NFKC)", value) + else + record.class.where("LOWER(NORMALIZE(#{attribute}, NFKC)) = LOWER(NORMALIZE(?, NFKC))", value) + end + + relation = relation.where.not(record.class.primary_key => [record.id_in_database]) if record.persisted? + + if relation.exists? + error_options = options.except(:case_sensitive) + error_options[:value] = value + + record.errors.add(attribute, :taken, **error_options) + end + end +end diff --git a/app/views/diary_entries/index.html.erb b/app/views/diary_entries/index.html.erb index e464b99b4..78ac0dcf8 100644 --- a/app/views/diary_entries/index.html.erb +++ b/app/views/diary_entries/index.html.erb @@ -14,15 +14,19 @@ diff --git a/app/views/issues/_comments.html.erb b/app/views/issues/_comments.html.erb index 9c5695e0a..7776d9ee3 100644 --- a/app/views/issues/_comments.html.erb +++ b/app/views/issues/_comments.html.erb @@ -7,7 +7,8 @@

<%= t ".comment_from_html", :user_link => link_to(comment.user.display_name, user_path(comment.user)), - :comment_created_at => l(comment.created_at.to_datetime, :format => :friendly) %> + :comment_created_at => tag.time(l(comment.created_at.to_datetime, :format => :friendly), + :datetime => comment.created_at.xmlschema) %>

<%= comment.body.to_html %>
diff --git a/app/views/issues/_reports.html.erb b/app/views/issues/_reports.html.erb index d11bca0a9..9ef28f1c2 100644 --- a/app/views/issues/_reports.html.erb +++ b/app/views/issues/_reports.html.erb @@ -7,7 +7,8 @@

<%= t ".reported_by_html", :category => report.category, :user => link_to(report.user.display_name, user_path(report.user)), - :updated_at => l(report.updated_at.to_datetime, :format => :friendly) %> + :updated_at => tag.time(l(report.updated_at.to_datetime, :format => :friendly), + :datetime => report.updated_at.xmlschema) %>

<%= report.details.to_html %>
diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb index 62bd501b7..e2099f8e6 100644 --- a/app/views/issues/show.html.erb +++ b/app/views/issues/show.html.erb @@ -9,9 +9,20 @@ <% else %> | <%= t ".no_reports" %> <% end %> - | <%= t ".report_created_at", :datetime => l(@issue.created_at.to_datetime, :format => :friendly) %> - <%= " | #{t('.last_resolved_at', :datetime => l(@issue.resolved_at.to_datetime, :format => :friendly))}" if @issue.resolved_at? %> - <%= " | #{t('.last_updated_at', :datetime => l(@issue.updated_at.to_datetime, :format => :friendly), :displayname => @issue.user_updated.display_name)}" if @issue.user_updated %> + | <%= t ".report_created_at_html", + :datetime => tag.time(l(@issue.created_at.to_datetime, :format => :friendly), + :datetime => @issue.created_at.xmlschema) %> + <% if @issue.resolved_at? %> + | <%= t ".last_resolved_at_html", + :datetime => tag.time(l(@issue.resolved_at.to_datetime, :format => :friendly), + :datetime => @issue.resolved_at.xmlschema) %> + <% end %> + <% if @issue.user_updated %> + | <%= t ".last_updated_at_html", + :datetime => tag.time(l(@issue.updated_at.to_datetime, :format => :friendly), + :datetime => @issue.updated_at.xmlschema), + :displayname => link_to(@issue.user_updated.display_name, user_path(@issue.user_updated)) %> + <% end %>