diff --git a/.erb_lint.yml b/.erb_lint.yml index 52ddcfd0aa525..00d73da81c5f8 100644 --- a/.erb_lint.yml +++ b/.erb_lint.yml @@ -24,6 +24,14 @@ linters: - text/template - application/ld+json + AdminPageTitleLinter: + enabled: true + exclude: + - decidim-admin/app/views/decidim/admin/shared/landing_page_content_blocks/edit.html.erb + - decidim-admin/app/views/decidim/admin/shared/landing_page/edit.html.erb + - decidim-admin/app/views/decidim/admin/imports/new.html.erb + - decidim-meetings/app/views/decidim/meetings/admin/poll/edit.html.erb + DeprecatedClasses: enabled: true exclude: diff --git a/.erb_linters/admin_page_title_linter.rb b/.erb_linters/admin_page_title_linter.rb new file mode 100644 index 0000000000000..7a201cfe2ff3c --- /dev/null +++ b/.erb_linters/admin_page_title_linter.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative "../decidim-dev/lib/erb_lint/linters/admin_page_title_linter" diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 54ba642be5ae0..cc6ad0b8f7327 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -19,6 +19,7 @@ activelog activemodel activerecord activestorage +actualitzar actualizado addlabel Adeu @@ -280,6 +281,7 @@ erblint Errbit Esa espa +estar estat etherpad evanfuture @@ -407,6 +409,7 @@ Ijkl ilike illgotten impersonatable +importmap inbox includeurl Indicacions @@ -512,6 +515,7 @@ markercluster marydoe Massot matrixmultiple +mattr matutes maxtimeout mcdoggo @@ -878,6 +882,7 @@ timeouter timestamped tiptap Tmpname +tms TLDR todos Tomorrowland diff --git a/.github/workflows/publiccode-yml-validation.yml b/.github/workflows/publiccode-yml-validation.yml index 96c2ef0c3aa52..50c8b329ccdfe 100644 --- a/.github/workflows/publiccode-yml-validation.yml +++ b/.github/workflows/publiccode-yml-validation.yml @@ -11,3 +11,4 @@ jobs: - uses: italia/publiccode-parser-action@v1 with: publiccode: 'publiccode.yml' + no-network: true diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml index 572b557bc604d..813b796847a64 100644 --- a/.github/workflows/test_app.yml +++ b/.github/workflows/test_app.yml @@ -141,7 +141,7 @@ jobs: with: name: ${{ inputs.working-directory }} flags: ${{ inputs.working-directory }} - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: always() with: name: Screenshots of run ${{ github.run_id }} diff --git a/Gemfile b/Gemfile index 294d62a2351f5..85852c1125bab 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ gem "decidim-elections", path: "." gem "decidim-initiatives", path: "." gem "decidim-templates", path: "." -gem "bootsnap", "~> 1.4" +gem "bootsnap", "~> 1.23" gem "puma", ">= 6.3.1" @@ -23,12 +23,12 @@ group :development, :test do gem "decidim-dev", path: "." - gem "brakeman", "~> 7.0" - gem "parallel_tests", "~> 4.2" + gem "brakeman", "~> 8.0" + gem "parallel_tests", "~> 5.6" end group :development do gem "letter_opener_web", "~> 3.0" - gem "listen", "~> 3.1" - gem "web-console", "~> 4.2" + gem "listen", "~> 3.10" + gem "web-console", "~> 4.3" end diff --git a/Gemfile.lock b/Gemfile.lock index b28081094ae02..24d321f7ef3f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -26,7 +26,7 @@ PATH decidim-admin (0.32.0.dev) active_link_to (~> 1.0) decidim-core (= 0.32.0.dev) - devise (~> 4.7) + devise (>= 4.7, < 6.0) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) decidim-ai (0.32.0.dev) @@ -34,10 +34,10 @@ PATH decidim-core (= 0.32.0.dev) decidim-api (0.32.0.dev) decidim-core (= 0.32.0.dev) - devise-jwt (~> 0.12.1) + devise-jwt (>= 0.12.1, < 0.14.0) graphql (>= 2.4.17, < 2.6) - graphql-docs (~> 5.0) - rack-cors (~> 1.0) + graphql-docs (>= 5, < 7) + rack-cors (>= 1, < 4) decidim-assemblies (0.32.0.dev) decidim-core (= 0.32.0.dev) decidim-blogs (0.32.0.dev) @@ -63,16 +63,16 @@ PATH cells-erb (~> 0.1.0) cells-rails (~> 0.1.3) charlock_holmes (~> 0.7) - chartkick (~> 5.1.2) + chartkick (>= 5.1.2, < 5.3.0) concurrent-ruby (~> 1.3.0) - connection_pool (< 3) + connection_pool (< 4) data_migrate (~> 11.3) date_validator (~> 0.12.0) - devise (~> 4.7) + devise (>= 4.7, < 6.0) devise-i18n (~> 1.2) diffy (~> 3.3) doorkeeper (~> 5.6, >= 5.6.6) - doorkeeper-i18n (~> 4.0) + doorkeeper-i18n (>= 4, < 6) file_validators (~> 3.0) fog-local (~> 0.6) geocoder (~> 1.8) @@ -86,23 +86,23 @@ PATH net-smtp (~> 0.5.0) nokogiri (~> 1.16, >= 1.16.2) omniauth (~> 2.0) - omniauth-facebook (~> 5.0) + omniauth-facebook (>= 5, < 11) omniauth-google-oauth2 (~> 1.0) - omniauth-rails_csrf_protection (~> 1.0) + omniauth-rails_csrf_protection (>= 1, < 3) omniauth-twitter (~> 1.4) - paper_trail (~> 16.0) - paranoia (~> 3.0.0) - pg (~> 1.5.0, < 2) + paper_trail (~> 17.0) + paranoia (~> 3.1.0) + pg (>= 1.5, < 1.7) pg_search (~> 2.2) premailer-rails (~> 1.10) rack (>= 3.2.4, < 4.0) - rack-attack (~> 6.7.0) - rails (~> 7.2.0, >= 7.2.3) - rails-i18n (~> 7.0) - ransack (~> 4.2.0) - redis (~> 4.1) + rack-attack (>= 6.7, < 6.9) + rails (~> 8.1.0) + rails-i18n (~> 8.1.0, < 8.2) + ransack (>= 4.2, < 4.5) + redis (>= 4.1, < 6.0) request_store (~> 1.7.0) - rqrcode (~> 2.2.0) + rqrcode (>= 2.2, < 3.3) ruby-vips (~> 2.2) rubyXL (~> 3.4) rubyzip (~> 2.0) @@ -119,7 +119,7 @@ PATH decidim-design (0.32.0.dev) decidim-core (= 0.32.0.dev) decidim-dev (0.32.0.dev) - bullet (~> 8.0.0) + bullet (~> 8.1.0) byebug (>= 11, < 14) capybara (~> 3.39) decidim-admin (= 0.32.0.dev) @@ -128,31 +128,31 @@ PATH decidim-core (= 0.32.0.dev) decidim-generators (= 0.32.0.dev) decidim-verifications (= 0.32.0.dev) - erb_lint (~> 0.8.0) + erb_lint (>= 0.8, < 0.10) factory_bot_rails (~> 6.2) faker (~> 3.2) i18n-tasks (~> 1.0) nokogiri (~> 1.16, >= 1.16.2) - parallel_tests (~> 4.2) - puma (~> 6.5) + parallel_tests (>= 4.2, < 6.0) + puma (>= 6.5, < 8.0) rails-controller-testing (~> 1.0) rspec (~> 3.12) rspec-cells (~> 0.3.7) rspec-html-matchers (~> 0.10) - rspec-rails (~> 6.0) + rspec-rails (>= 6, < 9) rspec-retry (~> 0.6.2) rspec_junit_formatter (~> 0.6.0) - rubocop (~> 1.78.0) + rubocop (>= 1.78, < 1.86) rubocop-capybara (~> 2.22.0, >= 2.22.1) - rubocop-factory_bot (~> 2.27.0) + rubocop-factory_bot (>= 2.27, < 2.29) rubocop-faker (~> 1.3, >= 1.3.0) rubocop-graphql (~> 1.5, >= 1.5.6) rubocop-performance (~> 1.25, >= 1.25.0) - rubocop-rails (~> 2.32.0, >= 2.32.0) + rubocop-rails (>= 2.32, < 2.35) rubocop-rspec (~> 3.0, >= 3.6.0) - rubocop-rspec_rails (~> 2.31.0) + rubocop-rspec_rails (>= 2.31, < 2.33) rubocop-rubycw (~> 0.2.0) - rubocop-yard (~> 1.0.0) + rubocop-yard (>= 1.0, < 1.2) selenium-webdriver (~> 4.9) simplecov (~> 0.22.0) simplecov-cobertura (~> 3.1.0) @@ -193,7 +193,7 @@ PATH decidim-system (0.32.0.dev) active_link_to (~> 1.0) decidim-core (= 0.32.0.dev) - devise (~> 4.7) + devise (>= 4.7, < 6.0) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) decidim-templates (0.32.0.dev) @@ -205,108 +205,108 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (7.2.3) - actionpack (= 7.2.3) - activesupport (= 7.2.3) + action_text-trix (2.1.17) + railties + actioncable (8.1.2) + actionpack (= 8.1.2) + activesupport (= 8.1.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.3) - actionpack (= 7.2.3) - activejob (= 7.2.3) - activerecord (= 7.2.3) - activestorage (= 7.2.3) - activesupport (= 7.2.3) + actionmailbox (8.1.2) + actionpack (= 8.1.2) + activejob (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) mail (>= 2.8.0) - actionmailer (7.2.3) - actionpack (= 7.2.3) - actionview (= 7.2.3) - activejob (= 7.2.3) - activesupport (= 7.2.3) + actionmailer (8.1.2) + actionpack (= 8.1.2) + actionview (= 8.1.2) + activejob (= 8.1.2) + activesupport (= 8.1.2) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.3) - actionview (= 7.2.3) - activesupport (= 7.2.3) - cgi + actionpack (8.1.2) + actionview (= 8.1.2) + activesupport (= 8.1.2) nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4, < 3.3) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.3) - actionpack (= 7.2.3) - activerecord (= 7.2.3) - activestorage (= 7.2.3) - activesupport (= 7.2.3) + actiontext (8.1.2) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.3) - activesupport (= 7.2.3) + actionview (8.1.2) + activesupport (= 8.1.2) builder (~> 3.1) - cgi erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_link_to (1.0.5) actionpack addressable - activejob (7.2.3) - activesupport (= 7.2.3) + activejob (8.1.2) + activesupport (= 8.1.2) globalid (>= 0.3.6) - activemodel (7.2.3) - activesupport (= 7.2.3) - activerecord (7.2.3) - activemodel (= 7.2.3) - activesupport (= 7.2.3) + activemodel (8.1.2) + activesupport (= 8.1.2) + activerecord (8.1.2) + activemodel (= 8.1.2) + activesupport (= 8.1.2) timeout (>= 0.4.0) - activestorage (7.2.3) - actionpack (= 7.2.3) - activejob (= 7.2.3) - activerecord (= 7.2.3) - activesupport (= 7.2.3) + activestorage (8.1.2) + actionpack (= 8.1.2) + activejob (= 8.1.2) + activerecord (= 8.1.2) + activesupport (= 8.1.2) marcel (~> 1.0) - activesupport (7.2.3) + activesupport (8.1.2) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - acts_as_list (1.2.4) + uri (>= 0.13.1) + acts_as_list (1.2.6) activerecord (>= 6.1) activesupport (>= 6.1) - addressable (2.8.8) + addressable (2.8.9) public_suffix (>= 2.0.2, < 8.0) ast (2.4.3) base64 (0.3.0) - batch-loader (2.0.5) - bcrypt (3.1.20) - benchmark (0.5.0) - better_html (2.1.1) - actionview (>= 6.0) - activesupport (>= 6.0) + batch-loader (2.0.6) + bcrypt (3.1.22) + better_html (2.2.0) + actionview (>= 7.0) + activesupport (>= 7.0) ast (~> 2.0) erubi (~> 1.4) parser (>= 2.4) smart_properties bigdecimal (4.0.1) bindex (0.8.1) - bootsnap (1.18.6) + bootsnap (1.23.0) msgpack (~> 1.2) - brakeman (7.0.2) + brakeman (8.0.4) racc browser (6.2.0) builder (3.3.0) - bullet (8.0.8) + bullet (8.1.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) byebug (13.0.0) @@ -331,9 +331,8 @@ GEM cells-rails (0.1.6) actionpack (>= 5.0) cells (>= 4.1.6, < 5.0.0) - cgi (0.5.1) charlock_holmes (0.7.9) - chartkick (5.1.5) + chartkick (5.2.1) childprocess (5.1.0) logger (~> 1.5) chunky_png (1.4.0) @@ -341,10 +340,11 @@ GEM fast-stemmer (~> 1.0) matrix (~> 0.4) cmdparse (3.0.7) - commonmarker (0.23.12) + commonmarker (2.6.3-arm64-darwin) + commonmarker (2.6.3-x86_64-linux) concurrent-ruby (1.3.6) - connection_pool (2.5.5) - crack (1.0.0) + connection_pool (3.0.2) + crack (1.0.1) bigdecimal rexml crass (1.0.6) @@ -361,16 +361,17 @@ GEM declarative-builder (0.2.0) trailblazer-option (~> 0.1.0) declarative-option (0.1.0) - devise (4.9.4) + devise (5.0.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 4.1.0) + railties (>= 7.0) responders warden (~> 1.2.3) - devise-i18n (1.12.1) - devise (>= 4.9.0) - devise-jwt (0.12.1) - devise (~> 4.0) + devise-i18n (1.16.0) + devise (>= 5.0.0) + rails-i18n + devise-jwt (0.13.0) + devise (>= 4.0.0, < 6.0.0) warden-jwt_auth (~> 0.10) devise_invitable (2.0.11) actionmailer (>= 5.0) @@ -381,9 +382,10 @@ GEM nokogiri (>= 1.18.2) rubyzip (~> 2.3.0) docile (1.4.1) - doorkeeper (5.8.2) + doorkeeper (5.9.0) railties (>= 5) - doorkeeper-i18n (4.0.1) + doorkeeper-i18n (5.2.8) + doorkeeper (>= 5.2) drb (2.2.3) dry-auto_inject (1.1.0) dry-core (~> 1.1) @@ -391,12 +393,12 @@ GEM dry-configurable (1.3.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-core (1.1.0) + dry-core (1.2.0) concurrent-ruby (~> 1.0) logger zeitwerk (~> 2.6) erb (6.0.2) - erb_lint (0.8.0) + erb_lint (0.9.0) activesupport better_html (>= 2.0.1) parser (>= 2.7.1.4) @@ -407,16 +409,14 @@ GEM temple erubi (1.13.1) escape_utils (1.3.0) - excon (1.2.8) + excon (1.3.2) logger - extended-markdown-filter (0.7.0) - html-pipeline (~> 2.9) - factory_bot (6.5.4) + factory_bot (6.5.6) activesupport (>= 6.1.0) - factory_bot_rails (6.4.4) + factory_bot_rails (6.5.1) factory_bot (~> 6.5) - railties (>= 5.0.0) - faker (3.5.3) + railties (>= 6.1.0) + faker (3.6.1) i18n (>= 1.8.11, < 2) faraday (2.14.1) faraday-net_http (>= 2.0, < 3.5) @@ -425,8 +425,8 @@ GEM faraday-net_http (3.4.2) net-http (~> 0.5) fast-stemmer (1.0.2) - ffi (1.17.2-arm64-darwin) - ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.3-arm64-darwin) + ffi (1.17.3-x86_64-linux-gnu) fiber-storage (1.0.1) file_validators (3.0.0) activemodel (>= 3.2) @@ -436,38 +436,39 @@ GEM excon (~> 1.0) formatador (>= 0.2, < 2.0) mime-types - fog-local (0.8.0) + fog-local (0.9.0) fog-core (>= 1.27, < 3.0) - formatador (1.1.1) - gemoji (3.0.1) - geocoder (1.8.5) + formatador (1.2.3) + reline + gemoji (4.1.0) + geocoder (1.8.6) base64 (>= 0.1.0) csv (>= 3.0.0) geom2d (0.4.1) globalid (1.3.0) activesupport (>= 6.1) - google-protobuf (4.29.3-arm64-darwin) + google-protobuf (4.33.5-arm64-darwin) bigdecimal rake (>= 13) - google-protobuf (4.29.3-x86_64-linux) + google-protobuf (4.33.5-x86_64-linux-gnu) bigdecimal rake (>= 13) - graphql (2.5.19) + graphql (2.5.21) base64 fiber-storage logger - graphql-docs (5.1.0) - commonmarker (~> 0.23, >= 0.23.6) + graphql-docs (6.0.0) + commonmarker (~> 2.0) escape_utils (~> 1.2) - extended-markdown-filter (~> 0.4) - gemoji (~> 3.0) + gemoji (~> 4.0) graphql (~> 2.0) - html-pipeline (~> 2.14, >= 2.14.3) + html-pipeline (~> 3.0) logger (~> 1.6) ostruct (~> 0.6) sass-embedded (~> 1.58) - hashdiff (1.1.2) - hashie (5.0.0) + hashdiff (1.2.1) + hashie (5.1.0) + logger hexapdf (1.6.0) cmdparse (~> 3.0, >= 3.0.3) geom2d (~> 0.4, >= 0.4.1) @@ -475,25 +476,28 @@ GEM strscan (>= 3.1.2) highline (3.1.2) reline - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) + html-pipeline (3.2.4) + selma (~> 0.4) + zeitwerk (~> 2.5) htmlentities (4.3.4) i18n (1.14.8) concurrent-ruby (~> 1.0) - i18n-tasks (1.0.15) + i18n-tasks (1.1.2) activesupport (>= 4.0.2) ast (>= 2.1.0) erubi - highline (>= 2.0.0) + highline (>= 3.0.0) i18n parser (>= 3.2.2.1) + prism rails-i18n rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.8, >= 1.8.1) terminal-table (>= 1.5.1) - icalendar (2.10.3) + icalendar (2.12.1) + base64 ice_cube (~> 0.16) + logger ostruct ice_cube (0.17.0) image_processing (1.14.0) @@ -507,7 +511,10 @@ GEM prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.18.1) + json (2.19.2) + json-schema (6.2.0) + addressable (~> 2.8) + bigdecimal (>= 3.1, < 5) jwt (3.1.2) base64 kaminari (1.2.2) @@ -535,11 +542,12 @@ GEM railties (>= 6.1) rexml lint_roller (1.1.0) - listen (3.9.0) + listen (3.10.0) + logger rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) - loofah (2.25.0) + loofah (2.25.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.9.0) @@ -550,10 +558,12 @@ GEM net-smtp marcel (1.1.0) matrix (0.4.3) - mime-types (3.6.0) + mcp (0.8.0) + json-schema (>= 4.1) + mime-types (3.7.0) logger - mime-types-data (~> 3.2015) - mime-types-data (3.2025.0722) + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2026.0224) mini_magick (5.3.1) logger mini_mime (1.1.5) @@ -575,9 +585,9 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.5) - nokogiri (1.19.1-arm64-darwin) + nokogiri (1.19.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.19.1-x86_64-linux-gnu) + nokogiri (1.19.2-x86_64-linux-gnu) racc (~> 1.4) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) @@ -585,21 +595,23 @@ GEM version_gem (~> 1.1) oauth-tty (1.0.5) version_gem (~> 1.1, >= 1.1.1) - oauth2 (2.0.12) + oauth2 (2.0.18) faraday (>= 0.17.3, < 4.0) jwt (>= 1.0, < 4.0) logger (~> 1.2) multi_xml (~> 0.5) rack (>= 1.2, < 4) snaky_hash (~> 2.0, >= 2.0.3) - version_gem (>= 1.1.8, < 3) - omniauth (2.1.3) + version_gem (~> 1.1, >= 1.1.9) + omniauth (2.1.4) hashie (>= 3.4.6) + logger rack (>= 2.2.3) rack-protection - omniauth-facebook (5.0.0) - omniauth-oauth2 (~> 1.2) - omniauth-google-oauth2 (1.2.1) + omniauth-facebook (10.0.0) + bigdecimal + omniauth-oauth2 (>= 1.2, < 3) + omniauth-google-oauth2 (1.2.2) jwt (>= 2.9.2) oauth2 (~> 2.0) omniauth (~> 2.0) @@ -608,10 +620,10 @@ GEM oauth omniauth (>= 1.0, < 3) rack (>= 1.6.2, < 4) - omniauth-oauth2 (1.8.0) - oauth2 (>= 1.4, < 3) + omniauth-oauth2 (1.9.0) + oauth2 (>= 2.0.2, < 3) omniauth (~> 2.0) - omniauth-rails_csrf_protection (1.0.2) + omniauth-rails_csrf_protection (2.0.1) actionpack (>= 4.2) omniauth (~> 2.0) omniauth-twitter (1.4.0) @@ -621,18 +633,19 @@ GEM orm_adapter (0.5.0) ostruct (0.6.3) package_json (0.1.0) - paper_trail (16.0.0) - activerecord (>= 6.1) + paper_trail (17.0.0) + activerecord (>= 7.1) request_store (~> 1.4) parallel (1.27.0) - parallel_tests (4.9.0) + parallel_tests (5.6.0) parallel - paranoia (3.0.1) - activerecord (>= 6, < 8.1) - parser (3.3.9.0) + paranoia (3.1.0) + activerecord (>= 7, < 8.2) + parser (3.3.10.2) ast (~> 2.4.1) racc - pg (1.5.9) + pg (1.6.3-arm64-darwin) + pg (1.6.3-x86_64-linux) pg_search (2.3.7) activerecord (>= 6.1) activesupport (>= 6.1) @@ -651,15 +664,16 @@ GEM psych (5.3.1) date stringio - public_suffix (7.0.2) - puma (6.5.0) + public_suffix (7.0.5) + puma (7.2.0) nio4r (~> 2.0) racc (1.8.1) rack (3.2.5) - rack-attack (6.7.0) + rack-attack (6.8.0) rack (>= 1.0, < 4) - rack-cors (1.1.1) - rack (>= 2.0.0) + rack-cors (3.0.0) + logger + rack (>= 3.0.14) rack-protection (4.2.1) base64 (>= 0.1.0) logger (>= 1.6.0) @@ -673,20 +687,20 @@ GEM rack (>= 1.3) rackup (2.3.1) rack (>= 3) - rails (7.2.3) - actioncable (= 7.2.3) - actionmailbox (= 7.2.3) - actionmailer (= 7.2.3) - actionpack (= 7.2.3) - actiontext (= 7.2.3) - actionview (= 7.2.3) - activejob (= 7.2.3) - activemodel (= 7.2.3) - activerecord (= 7.2.3) - activestorage (= 7.2.3) - activesupport (= 7.2.3) + rails (8.1.2) + actioncable (= 8.1.2) + actionmailbox (= 8.1.2) + actionmailer (= 8.1.2) + actionpack (= 8.1.2) + actiontext (= 8.1.2) + actionview (= 8.1.2) + activejob (= 8.1.2) + activemodel (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) bundler (>= 1.15.0) - railties (= 7.2.3) + railties (= 8.1.2) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -698,13 +712,12 @@ GEM rails-html-sanitizer (1.7.0) loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - rails-i18n (7.0.10) + rails-i18n (8.1.0) i18n (>= 0.7, < 2) - railties (>= 6.0.0, < 8) - railties (7.2.3) - actionpack (= 7.2.3) - activesupport (= 7.2.3) - cgi + railties (>= 8.0.0, < 9) + railties (8.1.2) + actionpack (= 8.1.2) + activesupport (= 8.1.2) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -713,9 +726,9 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.3.1) - ransack (4.2.1) - activerecord (>= 6.1.5) - activesupport (>= 6.1.5) + ransack (4.4.1) + activerecord (>= 7.2) + activesupport (>= 7.2) i18n rb-fsevent (0.11.2) rb-inotify (0.11.1) @@ -725,28 +738,31 @@ GEM psych (>= 4.0.0) tsort redcarpet (3.6.1) - redis (4.8.1) - regexp_parser (2.10.0) + redis (5.4.1) + redis-client (>= 0.22.0) + redis-client (0.27.0) + connection_pool + regexp_parser (2.11.3) reline (0.6.3) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) - responders (3.1.1) - actionpack (>= 5.2) - railties (>= 5.2) + responders (3.2.0) + actionpack (>= 7.0) + railties (>= 7.0) rexml (3.4.4) - rqrcode (2.2.0) + rqrcode (3.2.0) chunky_png (~> 1.0) - rqrcode_core (~> 1.0) - rqrcode_core (1.2.0) - rspec (3.13.1) + rqrcode_core (~> 2.0) + rqrcode_core (2.1.0) + rspec (3.13.2) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) rspec-cells (0.3.10) cells (>= 4.0.0, < 6.0.0) rspec-rails (>= 3.0.0) - rspec-core (3.13.5) + rspec-core (3.13.6) rspec-support (~> 3.13.0) rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) @@ -754,92 +770,95 @@ GEM rspec-html-matchers (0.10.0) nokogiri (~> 1) rspec (>= 3.0.0.a) - rspec-mocks (3.13.5) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.5) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-rails (8.0.4) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (>= 3.13.0, < 5.0.0) + rspec-expectations (>= 3.13.0, < 5.0.0) + rspec-mocks (>= 3.13.0, < 5.0.0) + rspec-support (>= 3.13.0, < 5.0.0) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.13.4) + rspec-support (3.13.7) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.78.0) + rubocop (1.85.1) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) + mcp (~> 0.6) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.45.1, < 2.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.45.1) + rubocop-ast (1.49.0) parser (>= 3.3.7.2) - prism (~> 1.4) + prism (~> 1.7) rubocop-capybara (2.22.1) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) - rubocop-factory_bot (2.27.1) + rubocop-factory_bot (2.28.0) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) rubocop-faker (1.3.0) faker (>= 2.12.0) lint_roller (~> 1.1) rubocop (>= 1.72.1) - rubocop-graphql (1.5.6) + rubocop-graphql (1.6.0) lint_roller (~> 1.1) rubocop (>= 1.72.1, < 2) - rubocop-performance (1.25.0) + rubocop-performance (1.26.1) lint_roller (~> 1.1) rubocop (>= 1.75.0, < 2.0) - rubocop-ast (>= 1.38.0, < 2.0) - rubocop-rails (2.32.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rails (2.34.3) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) rubocop (>= 1.75.0, < 2.0) rubocop-ast (>= 1.44.0, < 2.0) - rubocop-rspec (3.6.0) + rubocop-rspec (3.9.0) lint_roller (~> 1.1) - rubocop (~> 1.72, >= 1.72.1) - rubocop-rspec_rails (2.31.0) + rubocop (~> 1.81) + rubocop-rspec_rails (2.32.0) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) rubocop-rspec (~> 3.5) rubocop-rubycw (0.2.2) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) - rubocop-yard (1.0.0) + rubocop-yard (1.1.0) lint_roller rubocop (~> 1.72) yard ruby-progressbar (1.13.0) - ruby-vips (2.2.5) + ruby-vips (2.3.0) ffi (~> 1.12) logger rubyXL (3.4.33) nokogiri (>= 1.10.8) rubyzip (>= 1.3.0) rubyzip (2.3.2) - sass-embedded (1.83.4-arm64-darwin) - google-protobuf (~> 4.29) - sass-embedded (1.83.4-x86_64-linux-gnu) - google-protobuf (~> 4.29) + sass-embedded (1.97.3-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.97.3-x86_64-linux-gnu) + google-protobuf (~> 4.31) securerandom (0.4.1) - selenium-webdriver (4.27.0) + selenium-webdriver (4.41.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) + rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) + selma (0.4.15-arm64-darwin) + selma (0.4.15-x86_64-linux) semantic_range (3.1.0) shakapacker (8.3.0) activesupport (>= 5.2) @@ -860,7 +879,7 @@ GEM snaky_hash (2.0.3) hashie (>= 0.1.0, < 6) version_gem (>= 1.1.8, < 3) - spring (4.2.1) + spring (4.4.2) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) @@ -877,16 +896,16 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unicode-display_width (3.1.4) - unicode-emoji (~> 4.0, >= 4.0.4) - unicode-emoji (4.0.4) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) uniform_notifier (1.17.0) uri (1.1.1) useragent (0.16.11) valid_email2 (7.0.15) activemodel (>= 6.0) mail (~> 2.5) - version_gem (1.1.8) + version_gem (1.1.9) w3c_rspec_validators (0.3.0) rails rspec @@ -902,15 +921,14 @@ GEM dry-configurable (>= 0.13, < 2) jwt (>= 2.1, < 4) warden (~> 1.2) - web-console (4.2.1) - actionview (>= 6.0.0) - activemodel (>= 6.0.0) + web-console (4.3.0) + actionview (>= 8.0.0) bindex (>= 0.4.0) - railties (>= 6.0.0) + railties (>= 8.0.0) web-push (3.1.0) jwt (~> 3.0) openssl (>= 3.0) - webmock (3.24.0) + webmock (3.26.2) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -923,7 +941,7 @@ GEM wisper-rspec (1.1.0) xpath (3.2.0) nokogiri (~> 1.8) - yard (0.9.37) + yard (0.9.38) zeitwerk (2.7.5) PLATFORMS @@ -932,8 +950,8 @@ PLATFORMS x86_64-linux DEPENDENCIES - bootsnap (~> 1.4) - brakeman (~> 7.0) + bootsnap (~> 1.23) + brakeman (~> 8.0) byebug (~> 13.0) decidim! decidim-ai! @@ -946,10 +964,10 @@ DEPENDENCIES decidim-initiatives! decidim-templates! letter_opener_web (~> 3.0) - listen (~> 3.1) - parallel_tests (~> 4.2) + listen (~> 3.10) + parallel_tests (~> 5.6) puma (>= 6.3.1) - web-console (~> 4.2) + web-console (~> 4.3) RUBY VERSION ruby 3.4.7p58 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 619197596dbf2..bf20db8ab62e6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,7 +7,7 @@ checking out the last version of this document in the [GitHub page for the relea As usual, we recommend that you have a full backup, of the database, application code and static files. -NOTE: Please note this release is updating Rails version from 7.2.2 to 7.2.3. Please ensure you back up your `SECRET_KEY_BASE` env variable and also `tmp/local_secret.txt` if you have it. +NOTE: Please note this release is updating Rails version from 7.2.2 to 8.1.2. Ensure you back up your `SECRET_KEY_BASE` env variable and also `tmp/local_secret.txt` if you have it. On your local development environment, you may need to set your `SECRET_KEY_BASE` env variable to the same value as the one present in your `tmp/local_secret.txt`. To update, follow these steps: @@ -38,6 +38,7 @@ gem "decidim-dev", github: "decidim/decidim" sudo apt install libvips libvips-tools # or the alternative installation process for your operating system. See "3.5. Replace image processing with imagemagick to libvips" bundle update decidim bin/rails decidim:upgrade +sed -i "s/config\.load_defaults 7\.2/config\.load_defaults 8.1/g" config/application.rb # see "2.1. Ruby on Rails update to 8.1" bin/rails db:migrate bin/rails decidim:upgrade:encryption # skip this command if you have run it before: @@ -62,7 +63,24 @@ You can read more about this change on PR [#15005](https://github.com/decidim/de ## 2. General notes -### 2.1. Module deprecations +### 2.1. Ruby on Rails update to 8.1 + +This particular release is deploying a new Rails version, 8.1. As a result you need to update your application configuration. Before that, you need to run the following commands: + +```console +sed -i "s/config\.load_defaults 7\.2/config\.load_defaults 8.1/g" config/application.rb # see "2.1. Ruby on Rails update to 8.1" +``` + +#### Removal of official Azure support from Active Storage + +Rails core team decided to remove the Azure Active Storage support from Rails 8.1, as the official Azure libraries are not maintained since September 2024. If you are using Azure for your Active Storage, support, you could use the unofficial Azure Active Storage gem [Azure Blob](https://github.com/testdouble/azure-blob) + +You can read more about this change on PR: + +- [Upgrade to Rails 8.0.4](https://github.com/decidim/decidim/pull/16214) +- [Upgrade to Rails 8.1.2](https://github.com/decidim/decidim/pull/16310). + +### 2.2. Module deprecations As part of our ongoing efforts to improve and make simpler Decidim, the following modules will be **deprecated** in this version (v0.31) and **removed** in the next major version (v0.32): @@ -78,7 +96,7 @@ The Sortitions module (`decidim-sortitions`) is removed in v0.32. This module pr The Polls feature within the Meetings module (`decidim-meetings`) will be removed in a future version (to be determined). This feature allowed meeting organizers to create polls during meetings. Organizations using meeting polls should plan to use external polling tools (for instance, through Jitsi) or migrate to other voting mechanisms available in Decidim, such as the new Elections module (`decidim-elections`). -### 2.2. Old private exports are now expired +### 2.3. Old private exports are now expired Due to some data consistency issues with the private exports, we have decided to expire all the previously generated files. Users are able to request and receive a new private export file. @@ -92,13 +110,13 @@ bin/rails decidim:upgrade:clean:remove_private_exports_attachments You can read more about this change on PR [#15020](https://github.com/decidim/decidim/pull/15020). -### 2.3. Add data migrations +### 2.4. Add data migrations At the moment we are adding this gem so we can start doing data migrations for fixes when v0.33.0 is released. You can read more about this at [Data migrations doc](https://docs.decidim.org/en/develop/develop/guide_data_migrations.html). You can read more about this change on PR [#15501](https://github.com/decidim/decidim/pull/15501). -### 2.4. Fix gitignore for ServiceWorker related files +### 2.5. Fix gitignore for ServiceWorker related files We detected a bug where some dynamic files are not added to the gitignore, so they could be committed to the repository. For fixing it, you need to add them to your gitignore file: @@ -108,7 +126,7 @@ echo "/public/sw.js*" >> .gitignore You can read more about this change on PR [#15601](https://github.com/decidim/decidim/pull/15601). -### 2.5. Data migration for organization short_name +### 2.6. Data migration for organization short_name A new data migration has been added to populate the `short_name` field for existing organizations. This field is required for the PWA (Progressive Web App) manifest to properly display the application name on mobile devices' home screens. @@ -118,7 +136,7 @@ This migration runs automatically when executing `bin/rails data:migrate` as par You can read more about this change on PR [#15729](https://github.com/decidim/decidim/pull/15729). -### 2.6. Add locale to the url +### 2.7. Add locale to the url For a long time Decidim has been using internally the user browser to detect the language of the user. This has been changed to use the locale of the url instead. @@ -141,7 +159,7 @@ We are also removing the `decidim_user_group_memberships` tables. You can read more about this change on PR [#16022](https://github.com/decidim/decidim/pull/16022). -### 2.8. [[TITLE OF THE ACTION]] +### 2.9. [[TITLE OF THE ACTION]] You can read more about this change on PR [#XXXX](https://github.com/decidim/decidim/pull/XXXX). @@ -280,7 +298,88 @@ After the rack upgrade, the filters are defined as follows: You can read more about this change on PR [#16103](https://github.com/decidim/decidim/pull/16103). -### 5.3. [[TITLE OF THE CHANGE]] +### 5.3. Decidim Configuration changes + +Once you have upgraded to this version, you may need to check your configuration. Previously, we were using `ActiveSupport::Configurable` to handle Decidim configuration. Now, this has been deprecated with Rails, and it will be removed in the next Rails version. + +We went ahead and changed the way we handle Decidim configuration, trying to keep the same API as before. + +Previously, you may had an initializer with some content like: + +```ruby +Decidim.configure do |config| + config.force_ssl = true + # some other configuration +end +``` + +Now we try to keep the same, but if there is some kind of custom configuration that you may have, you will need to change it to: + +```ruby +Decidim.force_ssl = true +``` + +#### Decidim module developer instructions + +If you are a module developer, you may want to change your plugin structure to remove `ActiveSupport::Configurable` calls. + +If you were using something like: + +```ruby +module Decidim + module Ai + module SpamDetection + include ActiveSupport::Configurable + + config_accessor :reporting_user_email do + "my default value" + end + # some other configuration + end + end +end +``` + +You can refactor to the following: + +```ruby +module Decidim + module Ai + module SpamDetection + + mattr_accessor :reporting_user_email, default: "my default value" + + # some other configuration + end + end +end +``` + +To keep the same API, you may want to add the following to your module definition + +```ruby +module Decidim + module Ai + module SpamDetection + class << self + def config = self + + def configure + yield self + end + end + + mattr_accessor :reporting_user_email, default: "my default value" + + # some other configuration + end + end +end +``` + +You can read more about this change on PR [#16366](https://github.com/decidim/decidim/pull/16366). + +### 5.4. [[TITLE OF THE CHANGE]] In order to [[REASONING (e.g. improve the maintenance of the code base)]] we have changed... diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 12d2dfe08cd78..0057d76ebc5a0 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -162,13 +162,6 @@ ignore_unused: - decidim.elections.votes.check_census.* - decidim.elections.votes.question.* - decidim.proposals.answers.* - - decidim.proposals.collaborative_drafts.show.see_other_versions - - decidim.proposals.collaborative_drafts.wizard_aside.back - - decidim.proposals.collaborative_drafts.wizard_aside.back_from_collaborative_draft - - decidim.proposals.collaborative_drafts.wizard_aside.back_from_step_1 - - decidim.proposals.collaborative_drafts.wizard_aside.back_from_step_2 - - decidim.proposals.collaborative_drafts.wizard_aside.back_from_step_3 - - decidim.proposals.collaborative_drafts.wizard_aside.back_from_step_4 - decidim.proposals.proposal_likes_helper.likes_count_title - decidim.proposals.proposals.orders.* - decidim.proposals.proposals.likes_card_row.comments_title @@ -259,11 +252,6 @@ ignore_unused: - decidim.meetings.content_blocks.*.name - decidim.blogs.content_blocks.*.name - decidim.proposals.content_blocks.*.name - - decidim.proposals.collaborative_drafts.show.hidden_authors_count.* - - decidim.proposals.collaborative_drafts.orders* - - decidim.proposals.collaborative_drafts.filters* - - decidim.proposals.collaborative_drafts.show.withdraw - - decidim.proposals.collaborative_drafts.show.publish - decidim.conferences.content_blocks.*.name - decidim.conferences.pages.home.highlighted_conferences.* - decidim.conferences.conference_speaker.* diff --git a/decidim-accountability/app/cells/decidim/accountability/result_show_cell.rb b/decidim-accountability/app/cells/decidim/accountability/result_show_cell.rb index 5199b13934590..d9eb0bc0b56d3 100644 --- a/decidim-accountability/app/cells/decidim/accountability/result_show_cell.rb +++ b/decidim-accountability/app/cells/decidim/accountability/result_show_cell.rb @@ -8,6 +8,7 @@ module Accountability class ResultShowCell < Decidim::ViewModel include Decidim::Accountability::ApplicationHelper include Cell::ViewModel::Partial + delegate :children, :milestones, to: :model alias result model diff --git a/decidim-accountability/app/cells/decidim/accountability/status_cell.rb b/decidim-accountability/app/cells/decidim/accountability/status_cell.rb index 8ba35babf7e1f..dec94bd586a87 100644 --- a/decidim-accountability/app/cells/decidim/accountability/status_cell.rb +++ b/decidim-accountability/app/cells/decidim/accountability/status_cell.rb @@ -7,7 +7,7 @@ module Accountability # This cell renders the status of a taxonomy or a result. class StatusCell < Decidim::ViewModel include Decidim::Accountability::ApplicationHelper - include Decidim::Accountability::BreadcrumbHelper + include Decidim::Accountability::CalculatorHelper include ActionView::Helpers::NumberHelper def show @@ -80,10 +80,6 @@ def render_count options[:render_count] end - def count_calculator(taxonomy_id) - Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).count - end - def decidim Decidim::Accountability::Engine.routes.url_helpers end diff --git a/decidim-accountability/app/controllers/concerns/decidim/accountability/admin/filterable.rb b/decidim-accountability/app/controllers/concerns/decidim/accountability/admin/filterable.rb index d81e1646cb74e..ac879484908ad 100644 --- a/decidim-accountability/app/controllers/concerns/decidim/accountability/admin/filterable.rb +++ b/decidim-accountability/app/controllers/concerns/decidim/accountability/admin/filterable.rb @@ -44,7 +44,7 @@ def dynamically_translated_filters end def status_ids_hash(statuses) - statuses.each_with_object({}) { |status, hash| hash[status.id] = status.id } + statuses.to_h { |status| [status.id, status.id] } end def translated_status_id_eq(id) diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/import_components_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/import_components_controller.rb index 7059d2cbc914d..fcbcf6e038b51 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/import_components_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/import_components_controller.rb @@ -22,7 +22,7 @@ def create on(:invalid) do flash[:alert] = I18n.t("import_components.create.invalid", scope: "decidim.accountability.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/import_results_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/import_results_controller.rb index a1114a405c7c2..484e2c829a21a 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/import_results_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/import_results_controller.rb @@ -21,7 +21,7 @@ def create redirect_to import_results_path(current_participatory_space, current_component) else flash[:alert] = I18n.t("imports.create.invalid", scope: "decidim.accountability.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/milestones_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/milestones_controller.rb index 2747b12cef95e..dd878b20dddad 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/milestones_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/milestones_controller.rb @@ -27,7 +27,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("milestones.create.invalid", scope: "decidim.accountability.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -51,7 +51,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("milestones.update.invalid", scope: "decidim.accountability.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb index a89efd03afd5c..20ef9ad67aec6 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb @@ -88,12 +88,12 @@ def result_ids end def result_params - @result_params ||= params.require(:result_bulk_actions).permit( - :decidim_accountability_status_id, - :start_date, - :end_date, - result_ids: [], - taxonomies: [] + @result_params ||= params.expect( + result_bulk_actions: [:decidim_accountability_status_id, + :start_date, + :end_date, + { result_ids: [], + taxonomies: [] }] ) end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/results_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/results_controller.rb index 2b169f93d4c13..4adce6cfac7dd 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/results_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/results_controller.rb @@ -38,7 +38,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("results.create.invalid", scope: "decidim.accountability.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -62,7 +62,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("results.update.invalid", scope: "decidim.accountability.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/admin/statuses_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/admin/statuses_controller.rb index af990f2fa6633..af66db17b2041 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/admin/statuses_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/admin/statuses_controller.rb @@ -28,7 +28,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("statuses.create.invalid", scope: "decidim.accountability.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -52,7 +52,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("statuses.update.invalid", scope: "decidim.accountability.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-accountability/app/controllers/decidim/accountability/results_controller.rb b/decidim-accountability/app/controllers/decidim/accountability/results_controller.rb index 4b5bf0fb88435..cd9fb087d6cb2 100644 --- a/decidim-accountability/app/controllers/decidim/accountability/results_controller.rb +++ b/decidim-accountability/app/controllers/decidim/accountability/results_controller.rb @@ -5,10 +5,12 @@ module Accountability # Exposes the result resource so users can view them class ResultsController < Decidim::Accountability::ApplicationController include FilterResource + helper Decidim::TraceabilityHelper helper Decidim::Accountability::BreadcrumbHelper + helper Decidim::Accountability::CalculatorHelper - helper_method :results, :result, :count_calculator, :selected_root_taxonomy, :selected_taxonomy_children, :selected_taxonomy_grandchildren? + helper_method :results, :result, :selected_root_taxonomy, :selected_taxonomy_children, :selected_taxonomy_grandchildren? def show raise ActionController::RoutingError, "Not Found" unless result @@ -64,10 +66,6 @@ def selected_root_taxonomy end end - def count_calculator(taxonomy_id) - Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).count - end - def add_parent_breadcrumb_item return {} if result&.parent.blank? diff --git a/decidim-accountability/app/helpers/decidim/accountability/breadcrumb_helper.rb b/decidim-accountability/app/helpers/decidim/accountability/breadcrumb_helper.rb index 215d9c96c4bf7..fd4d16afec83a 100644 --- a/decidim-accountability/app/helpers/decidim/accountability/breadcrumb_helper.rb +++ b/decidim-accountability/app/helpers/decidim/accountability/breadcrumb_helper.rb @@ -5,10 +5,6 @@ module Accountability # Helpers needed to render the navigation breadcrumbs in results. # module BreadcrumbHelper - def progress_calculator(taxonomy_id) - Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).progress - end - def taxonomy return if (taxonomy_id = params.dig(:filter, :taxonomies_part_of_contains)).blank? diff --git a/decidim-accountability/app/helpers/decidim/accountability/calculator_helper.rb b/decidim-accountability/app/helpers/decidim/accountability/calculator_helper.rb new file mode 100644 index 0000000000000..7e99b8764dfab --- /dev/null +++ b/decidim-accountability/app/helpers/decidim/accountability/calculator_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Decidim + module Accountability + # Helpers for calculating results progress and count + module CalculatorHelper + def progress_calculator(taxonomy_id) + ResultsCalculator.new(current_component, taxonomy_id).progress + end + + def count_calculator(taxonomy_id) + ResultsCalculator.new(current_component, taxonomy_id).count + end + end + end +end diff --git a/decidim-accountability/app/mailers/decidim/accountability/import_projects_mailer.rb b/decidim-accountability/app/mailers/decidim/accountability/import_projects_mailer.rb index 444c8dffbc9e2..b070e2347f39b 100644 --- a/decidim-accountability/app/mailers/decidim/accountability/import_projects_mailer.rb +++ b/decidim-accountability/app/mailers/decidim/accountability/import_projects_mailer.rb @@ -6,6 +6,7 @@ module Accountability # projects from one budget component to accountability. class ImportProjectsMailer < Decidim::ApplicationMailer include Decidim::TranslatableAttributes + helper Decidim::TranslationsHelper # Public: Sends a notification email with the result of importing projects diff --git a/decidim-accountability/app/mailers/decidim/accountability/import_proposals_mailer.rb b/decidim-accountability/app/mailers/decidim/accountability/import_proposals_mailer.rb index 1b301987ccae7..2e52d41417f0b 100644 --- a/decidim-accountability/app/mailers/decidim/accountability/import_proposals_mailer.rb +++ b/decidim-accountability/app/mailers/decidim/accountability/import_proposals_mailer.rb @@ -6,6 +6,7 @@ module Accountability # proposals to the results. class ImportProposalsMailer < Decidim::ApplicationMailer include Decidim::TranslatableAttributes + helper Decidim::TranslationsHelper # Public: Sends a notification email with the result of proposals import selected proposals to Accountability diff --git a/decidim-accountability/lib/decidim/accountability/component.rb b/decidim-accountability/lib/decidim/accountability/component.rb index 92f3dc36949bd..0f6564f3b04d4 100644 --- a/decidim-accountability/lib/decidim/accountability/component.rb +++ b/decidim-accountability/lib/decidim/accountability/component.rb @@ -14,14 +14,12 @@ component.on(:publish) do |instance| Decidim::Accountability::Result.where(component: instance).find_each do |result| Decidim::UpdateSearchIndexesJob.perform_later([result]) - Decidim::UpdateSearchIndexesJob.perform_later(result.children.to_a) end end component.on(:unpublish) do |instance| Decidim::Accountability::Result.where(component: instance).find_each do |result| Decidim::RemoveSearchIndexesJob.perform_later([result]) - Decidim::UpdateSearchIndexesJob.perform_later(result.children.to_a) end end diff --git a/decidim-accountability/spec/cells/decidim/accountability/status_cell_spec.rb b/decidim-accountability/spec/cells/decidim/accountability/status_cell_spec.rb new file mode 100644 index 0000000000000..192dbcb724330 --- /dev/null +++ b/decidim-accountability/spec/cells/decidim/accountability/status_cell_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim::Accountability + describe StatusCell, type: :cell do + controller Decidim::Accountability::ResultsController + + let!(:component) { create(:accountability_component) } + let!(:taxonomy) { create(:taxonomy, :with_parent, organization: component.organization) } + let!(:result) { create(:result, component:, progress: 50) } + let(:component_settings) { double(display_progress_enabled?: true) } + + def status_cell(model, options = {}) + cell("decidim/accountability/status", model, options).tap do |cell| + allow(cell).to receive(:component_settings).and_return(component_settings) + allow(cell).to receive(:current_component).and_return(component) + end + end + + context "when rendering a taxonomy" do + let(:model) { taxonomy } + + context "with results" do + let!(:result) { create(:result, component:, taxonomies: [taxonomy], progress: 75) } + + it "renders the status" do + html = status_cell(taxonomy).call + expect(html).to have_css(".accountability__status") + end + + it "shows the progress" do + html = status_cell(taxonomy).call + expect(html).to have_content("75%") + end + end + + context "with no results" do + it "does not render" do + expect(status_cell(taxonomy).render?).to be false + end + end + end + + context "when rendering a result" do + let(:model) { result } + + it "renders the status" do + html = status_cell(result).call + expect(html).to have_css(".accountability__status") + end + + it "shows the progress from the model" do + html = status_cell(result).call + expect(html).to have_content("50%") + end + end + + context "with custom progress passed via options" do + let(:model) { result } + + it "does not use custom progress when model has progress" do + html = status_cell(result, progress: 80).call + expect(html).to have_content("50%") + expect(html).to have_no_content("80%") + end + end + + context "with custom count passed via options" do + let(:model) { result } + + it "displays the count" do + html = status_cell(result, count: 42).call + expect(html).to have_content("42") + end + end + + context "when render_blank option is true" do + let(:model) { taxonomy } + + it "renders even without results" do + expect(status_cell(taxonomy, render_blank: true).render?).to be true + end + end + + context "when render_count is false" do + let(:model) { result } + + it "does not display the count" do + html = status_cell(result, count: 99, render_count: false).call.to_s + expect(html).not_to include(">99<") + end + end + end +end diff --git a/decidim-accountability/spec/helpers/decidim/accountability/calculator_helper_spec.rb b/decidim-accountability/spec/helpers/decidim/accountability/calculator_helper_spec.rb new file mode 100644 index 0000000000000..80154700c09dc --- /dev/null +++ b/decidim-accountability/spec/helpers/decidim/accountability/calculator_helper_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim::Accountability + describe CalculatorHelper do + let(:participatory_process) { create(:participatory_process, :with_steps) } + let(:current_component) { create(:accountability_component, participatory_space: participatory_process) } + let(:taxonomy) { create(:taxonomy, :with_parent, organization: current_component.organization) } + let(:sub_taxonomy) { create(:taxonomy, parent: taxonomy, organization: current_component.organization) } + + let!(:result1) do + create( + :result, + component: current_component, + taxonomies: [taxonomy], + parent: nil, + progress: 40 + ) + end + let!(:result2) do + create( + :result, + component: current_component, + taxonomies: [taxonomy, sub_taxonomy], + parent: nil, + progress: 20 + ) + end + let!(:result3) do + create( + :result, + component: current_component, + taxonomies: [sub_taxonomy], + parent: nil, + progress: nil + ) + end + let!(:result4) do + create( + :result, + component: current_component, + parent: nil, + progress: 50 + ) + end + + before do + allow(helper).to receive(:current_component).and_return(current_component) + end + + describe "#progress_calculator" do + it "calculates the average progress for all results when no taxonomy_id is given" do + expect(helper.progress_calculator(nil)).to eq(27.5) + end + + it "calculates the average progress for a specific taxonomy (including children)" do + expect(helper.progress_calculator(taxonomy.id)).to eq(20) + end + + it "handles taxonomy with no results gracefully" do + other_taxonomy = create(:taxonomy, organization: current_component.organization) + expect(helper.progress_calculator(other_taxonomy.id)).to be_nil + end + end + + describe "#count_calculator" do + it "counts all results when no taxonomy_id is given" do + expect(helper.count_calculator(nil)).to eq(4) + end + + it "counts results for a specific taxonomy (including children)" do + expect(helper.count_calculator(taxonomy.id)).to eq(3) + end + + it "handles taxonomy with no results" do + other_taxonomy = create(:taxonomy, organization: current_component.organization) + expect(helper.count_calculator(other_taxonomy.id)).to eq(0) + end + end + end +end diff --git a/decidim-accountability/spec/system/admin/admin_manages_component_publication_spec.rb b/decidim-accountability/spec/system/admin/admin_manages_component_publication_spec.rb new file mode 100644 index 0000000000000..101cd561bc080 --- /dev/null +++ b/decidim-accountability/spec/system/admin/admin_manages_component_publication_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages component publication" do + include_context "when managing a component as an admin" do + context "when there are no children" do + let!(:resource) { create(:result, component:) } + + context "when cycling through publication states" do + let!(:component) { create(:accountability_component, participatory_space:) } + + include_examples "cycling through publication states" + end + + context "when component is unpublished, and admin publishes" do + let!(:component) { create(:accountability_component, :unpublished, participatory_space:) } + + include_examples "add component resources to search index" + end + + context "when component is published, and admin unpublishes" do + let!(:component) { create(:accountability_component, :published, participatory_space:) } + + include_examples "removes component resources from search index" + end + end + + context "when there are children" do + let!(:resource) { create(:result, component:) } + let!(:children) { create(:result, component:, parent: resource) } + + context "when cycling through publication states" do + let!(:component) { create(:accountability_component, participatory_space:) } + + include_examples "cycling through publication states" + end + + context "when component is unpublished, and admin publishes" do + let!(:component) { create(:accountability_component, :unpublished, participatory_space:) } + + include_examples "add component resources to search index" + end + + context "when component is published, and admin unpublishes" do + let!(:component) { create(:accountability_component, :published, participatory_space:) } + + include_examples "removes component resources from search index" + end + end + end +end diff --git a/decidim-accountability/spec/system/admin/admin_publishes_component_spec.rb b/decidim-accountability/spec/system/admin/admin_publishes_component_spec.rb deleted file mode 100644 index df961d66c13d1..0000000000000 --- a/decidim-accountability/spec/system/admin/admin_publishes_component_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Admin publishes component" do - let(:manifest_name) { "accountability" } - let!(:resource) { create(:result, component:) } - - include_context "when publishing and unpublishing the component" - include_context "when cycling through publication states" -end diff --git a/decidim-admin/app/cells/decidim/admin/content_block/show.erb b/decidim-admin/app/cells/decidim/admin/content_block/show.erb index 33489bbad5023..180f89352c6b0 100644 --- a/decidim-admin/app/cells/decidim/admin/content_block/show.erb +++ b/decidim-admin/app/cells/decidim/admin/content_block/show.erb @@ -12,7 +12,7 @@ <%= icon "delete-bin-line", role: "img", "aria-hidden": true %> <% end %> <% end %> - <%= icon "menu-line", role: "img", "aria-hidden": true %> + <%= icon("draggable", class: "dragger hover:cursor-grab") %> diff --git a/decidim-admin/app/commands/decidim/admin/content_blocks/reorder_content_blocks.rb b/decidim-admin/app/commands/decidim/admin/content_blocks/reorder_content_blocks.rb index f61eb5f570c13..6036f63b5ef6a 100644 --- a/decidim-admin/app/commands/decidim/admin/content_blocks/reorder_content_blocks.rb +++ b/decidim-admin/app/commands/decidim/admin/content_blocks/reorder_content_blocks.rb @@ -59,7 +59,7 @@ def set_new_weights data.each do |id, weight| content_block = collection.find_by(id:) - content_block.update!(weight:) if content_block.present? + (content_block.presence&.update!(weight:)) end end diff --git a/decidim-admin/app/commands/decidim/admin/participatory_space/create_member.rb b/decidim-admin/app/commands/decidim/admin/participatory_space/create_member.rb index 32ad418fa1f7f..8e62d3c06e215 100644 --- a/decidim-admin/app/commands/decidim/admin/participatory_space/create_member.rb +++ b/decidim-admin/app/commands/decidim/admin/participatory_space/create_member.rb @@ -52,12 +52,11 @@ def create_member title: user.name } ) do - Decidim::ParticipatorySpace::Member.find_or_create_by!( - user:, - participatory_space: @member_to, - role: form.role, - published: form.published - ) + member = Decidim::ParticipatorySpace::Member.where(user:, participatory_space: @member_to).first_or_initialize + member.role = form.role + member.published = form.published + member.save! + member end end diff --git a/decidim-admin/app/commands/decidim/admin/reorder_components.rb b/decidim-admin/app/commands/decidim/admin/reorder_components.rb index b15816194a560..abbf08ce77b32 100644 --- a/decidim-admin/app/commands/decidim/admin/reorder_components.rb +++ b/decidim-admin/app/commands/decidim/admin/reorder_components.rb @@ -38,7 +38,7 @@ def reorder_components transaction do order.each_with_index do |id, index| component = components.find_by(id:) - component.update!(weight: index + 1) if component.present? + (component.presence&.update!(weight: index + 1)) end end end diff --git a/decidim-admin/app/commands/decidim/admin/reorder_taxonomies.rb b/decidim-admin/app/commands/decidim/admin/reorder_taxonomies.rb index 9a4d0fdd5ce6b..b86e4eb113176 100644 --- a/decidim-admin/app/commands/decidim/admin/reorder_taxonomies.rb +++ b/decidim-admin/app/commands/decidim/admin/reorder_taxonomies.rb @@ -54,7 +54,7 @@ def set_new_weights data.each do |id, weight| item = collection.find_by(id:) - item.update!(weight:) if item.present? + (item.presence&.update!(weight:)) end end diff --git a/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page.rb b/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page.rb index ca2606884bf47..4ef394de1ba6d 100644 --- a/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page.rb +++ b/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page.rb @@ -5,6 +5,7 @@ module Admin module ContentBlocks module LandingPage extend ActiveSupport::Concern + included do helper_method :active_blocks, :active_content_blocks_title, :add_content_block_text, :available_manifests, :content_block_destroy_confirmation_text, :content_blocks_title, :inactive_blocks, diff --git a/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page_content_blocks.rb b/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page_content_blocks.rb index 442455b728e78..bc5d5feecd4db 100644 --- a/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page_content_blocks.rb +++ b/decidim-admin/app/controllers/concerns/decidim/admin/content_blocks/landing_page_content_blocks.rb @@ -5,6 +5,7 @@ module Admin module ContentBlocks module LandingPageContentBlocks extend ActiveSupport::Concern + included do helper_method :content_block, :resource_landing_page_content_block_path, :scoped_resource, :submit_button_text @@ -55,7 +56,7 @@ def update redirect_to edit_resource_landing_page_path end on(:invalid) do - render "decidim/admin/shared/landing_page_content_blocks/edit", status: :unprocessable_entity + render "decidim/admin/shared/landing_page_content_blocks/edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/concerns/decidim/admin/filterable.rb b/decidim-admin/app/controllers/concerns/decidim/admin/filterable.rb index 0a6efac8893d5..6061e771fc266 100644 --- a/decidim-admin/app/controllers/concerns/decidim/admin/filterable.rb +++ b/decidim-admin/app/controllers/concerns/decidim/admin/filterable.rb @@ -77,7 +77,7 @@ def session_filtered_collection # the query def adjacent_items(item) query = - <<-SQL.squish + <<~SQL.squish WITH collection AS (#{session_filtered_collection.select(:id).to_sql}), successors AS ( @@ -198,8 +198,8 @@ def taxonomy_ids_hash(taxonomies) filtered_taxonomies = taxonomies.roots.or(taxonomies.where(id: available_taxonomy_ids)) return nil if filtered_taxonomies.blank? - filtered_taxonomies.each_with_object({}) do |taxonomy, hash| - hash[taxonomy.id] = taxonomy_ids_hash(taxonomy.children) + filtered_taxonomies.to_h do |taxonomy| + [taxonomy.id, taxonomy_ids_hash(taxonomy.children)] end end diff --git a/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_admin_context.rb b/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_admin_context.rb index 330814cd27dad..b29432c6087f3 100644 --- a/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_admin_context.rb +++ b/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_admin_context.rb @@ -25,6 +25,7 @@ def participatory_space_admin_layout(options = {}) included do include Decidim::NeedsOrganization include Decidim::Admin::ParticipatorySpaceAdminBreadcrumb + helper ParticipatorySpaceHelpers helper_method :current_participatory_space diff --git a/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_export.rb b/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_export.rb index 00d40c785bd59..eb4f2fa227446 100644 --- a/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_export.rb +++ b/decidim-admin/app/controllers/concerns/decidim/admin/participatory_space_export.rb @@ -17,7 +17,7 @@ def create flash[:notice] = t("decidim.admin.exports.notice") - redirect_back(fallback_location: after_export_path) + redirect_back_or_to(after_export_path) end # Public: To be implemented at the controller. You need to diff --git a/decidim-admin/app/controllers/decidim/admin/area_types_controller.rb b/decidim-admin/app/controllers/decidim/admin/area_types_controller.rb index 58e292449eddd..236cf11ee5caa 100644 --- a/decidim-admin/app/controllers/decidim/admin/area_types_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/area_types_controller.rb @@ -34,7 +34,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("area_types.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -56,7 +56,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("area_types.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/areas_controller.rb b/decidim-admin/app/controllers/decidim/admin/areas_controller.rb index 633128e18fc6b..d5c9b09891126 100644 --- a/decidim-admin/app/controllers/decidim/admin/areas_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/areas_controller.rb @@ -6,6 +6,7 @@ module Admin # class AreasController < Decidim::Admin::ApplicationController include Decidim::Admin::Concerns::HasTabbedMenu + helper Decidim::Admin::AreasHelper layout "decidim/admin/settings" @@ -35,7 +36,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("areas.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -57,7 +58,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("areas.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb b/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb index 4cc2cf264069e..ccc9825a8ec85 100644 --- a/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb @@ -27,7 +27,7 @@ def create on(:invalid) do flash[:alert] = I18n.t("officializations.block.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -65,7 +65,7 @@ def bulk_create on(:invalid) do flash.now[:alert] = I18n.t("officializations.bulk_action.block.invalid", scope: "decidim.admin") - render :bulk_new, status: :unprocessable_entity + render :bulk_new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/component_permissions_controller.rb b/decidim-admin/app/controllers/decidim/admin/component_permissions_controller.rb index 5b795d9531d56..5a32bf3a4ce45 100644 --- a/decidim-admin/app/controllers/decidim/admin/component_permissions_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/component_permissions_controller.rb @@ -26,7 +26,7 @@ def update on(:invalid) do flash.now[:alert] = t("component_permissions.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/components/base_controller.rb b/decidim-admin/app/controllers/decidim/admin/components/base_controller.rb index f2dd0a5b924ad..956bc922c6223 100644 --- a/decidim-admin/app/controllers/decidim/admin/components/base_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/components/base_controller.rb @@ -10,6 +10,7 @@ class BaseController < Decidim::Admin::ApplicationController include Decidim::Admin::ParticipatorySpaceAdminContext include Decidim::NeedsPermission + participatory_space_admin_layout helper Decidim::ResourceHelper diff --git a/decidim-admin/app/controllers/decidim/admin/components_controller.rb b/decidim-admin/app/controllers/decidim/admin/components_controller.rb index a25e5e55d0b26..87acf4df5ec4a 100644 --- a/decidim-admin/app/controllers/decidim/admin/components_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/components_controller.rb @@ -7,6 +7,7 @@ module Admin # class ComponentsController < Decidim::Admin::ApplicationController include Decidim::Admin::HasTrashableResources + helper_method :manifest def index @@ -47,7 +48,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("components.create.error", scope: "decidim.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -74,7 +75,7 @@ def update on(:invalid) do flash[:alert] = I18n.t("components.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/concerns/has_attachment_collections.rb b/decidim-admin/app/controllers/decidim/admin/concerns/has_attachment_collections.rb index 9fcb4f605ece9..5c194971506ce 100644 --- a/decidim-admin/app/controllers/decidim/admin/concerns/has_attachment_collections.rb +++ b/decidim-admin/app/controllers/decidim/admin/concerns/has_attachment_collections.rb @@ -39,7 +39,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("attachment_collections.create.error", scope: "decidim.admin") - render template: "decidim/admin/attachment_collections/new", status: :unprocessable_entity + render template: "decidim/admin/attachment_collections/new", status: :unprocessable_content end end end @@ -64,7 +64,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("attachment_collections.update.error", scope: "decidim.admin") - render template: "decidim/admin/attachment_collections/edit", status: :unprocessable_entity + render template: "decidim/admin/attachment_collections/edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/concerns/has_attachments.rb b/decidim-admin/app/controllers/decidim/admin/concerns/has_attachments.rb index 09e6258cd5cff..27170ed202fb9 100644 --- a/decidim-admin/app/controllers/decidim/admin/concerns/has_attachments.rb +++ b/decidim-admin/app/controllers/decidim/admin/concerns/has_attachments.rb @@ -39,7 +39,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("attachments.create.error", scope: "decidim.admin") - render template: "decidim/admin/attachments/new", status: :unprocessable_entity + render template: "decidim/admin/attachments/new", status: :unprocessable_content end end end @@ -64,7 +64,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("attachments.update.error", scope: "decidim.admin") - render template: "decidim/admin/attachments/edit", status: :unprocessable_entity + render template: "decidim/admin/attachments/edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/conflicts_controller.rb b/decidim-admin/app/controllers/decidim/admin/conflicts_controller.rb index df31593a8fa03..d29163c060bff 100644 --- a/decidim-admin/app/controllers/decidim/admin/conflicts_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/conflicts_controller.rb @@ -47,7 +47,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("error", scope: "decidim.admin.conflicts.transfer") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/exports_controller.rb b/decidim-admin/app/controllers/decidim/admin/exports_controller.rb index f2ee8459aaad8..7bac95186c120 100644 --- a/decidim-admin/app/controllers/decidim/admin/exports_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/exports_controller.rb @@ -15,7 +15,7 @@ def create flash[:notice] = t("decidim.admin.exports.notice") - redirect_back(fallback_location: manage_component_path(component)) + redirect_back_or_to(manage_component_path(component)) end private diff --git a/decidim-admin/app/controllers/decidim/admin/impersonations_controller.rb b/decidim-admin/app/controllers/decidim/admin/impersonations_controller.rb index 1e652ec6d8a09..f973704e1d324 100644 --- a/decidim-admin/app/controllers/decidim/admin/impersonations_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/impersonations_controller.rb @@ -46,7 +46,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("impersonations.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/imports_controller.rb b/decidim-admin/app/controllers/decidim/admin/imports_controller.rb index 1bf139e13f007..fd1a96317f7e5 100644 --- a/decidim-admin/app/controllers/decidim/admin/imports_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/imports_controller.rb @@ -5,6 +5,7 @@ module Admin # This controller allows admins to import resources from a file. class ImportsController < Decidim::Admin::ApplicationController include Decidim::ComponentPathHelper + before_action :set_import_breadcrumb_item helper_method :import_manifest @@ -39,7 +40,7 @@ def create on(:invalid) do flash.now[:alert] = t("decidim.admin.imports.error") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/managed_users/promotions_controller.rb b/decidim-admin/app/controllers/decidim/admin/managed_users/promotions_controller.rb index 822d147855d4f..a1dd1e6ccbda3 100644 --- a/decidim-admin/app/controllers/decidim/admin/managed_users/promotions_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/managed_users/promotions_controller.rb @@ -25,7 +25,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("managed_users.promotion.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb b/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb index 2112c9528b1dc..95b84382b8968 100644 --- a/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb @@ -7,6 +7,7 @@ class NewslettersController < Decidim::Admin::ApplicationController include Decidim::NewslettersHelper include Decidim::Admin::NewslettersHelper include Paginable + helper_method :newsletter, :recipients_count_query, :content_block, :selected_options, :newsletter_params def index @@ -31,7 +32,7 @@ def send_to_user NewsletterMailer.newsletter(current_user, newsletter).deliver_later flash[:notice] = I18n.t("newsletters.send_to_user.sent_successfully", scope: "decidim.admin", email: current_user.email) - redirect_back fallback_location: newsletters_path + redirect_back_or_to(newsletters_path) end def preview @@ -56,7 +57,7 @@ def create on(:invalid) do |newsletter| @newsletter = newsletter flash.now[:error] = I18n.t("newsletters.create.error", scope: "decidim.admin") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end @@ -80,7 +81,7 @@ def update on(:invalid) do |newsletter| @newsletter = newsletter flash.now[:error] = I18n.t("newsletters.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end @@ -128,12 +129,12 @@ def deliver on(:invalid) do flash.now[:error] = I18n.t("newsletters.deliver.error", scope: "decidim.admin") - render action: :select_recipients_to_deliver, status: :unprocessable_entity + render action: :select_recipients_to_deliver, status: :unprocessable_content end on(:no_recipients) do flash.now[:error] = I18n.t("newsletters.send.no_recipients", scope: "decidim.admin") - render action: :select_recipients_to_deliver, status: :unprocessable_entity + render action: :select_recipients_to_deliver, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/organization_appearance_controller.rb b/decidim-admin/app/controllers/decidim/admin/organization_appearance_controller.rb index 79f2adcf8d852..acaf3f53b2280 100644 --- a/decidim-admin/app/controllers/decidim/admin/organization_appearance_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/organization_appearance_controller.rb @@ -25,7 +25,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("organization.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/organization_controller.rb b/decidim-admin/app/controllers/decidim/admin/organization_controller.rb index c49e5edcca701..217f3b2963f7d 100644 --- a/decidim-admin/app/controllers/decidim/admin/organization_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/organization_controller.rb @@ -29,7 +29,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("organization.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/organization_external_domain_allowlist_controller.rb b/decidim-admin/app/controllers/decidim/admin/organization_external_domain_allowlist_controller.rb index d986fbb8f6f5f..fb8c7eabf59ae 100644 --- a/decidim-admin/app/controllers/decidim/admin/organization_external_domain_allowlist_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/organization_external_domain_allowlist_controller.rb @@ -25,7 +25,7 @@ def update end on(:invalid) do flash[:notice] = t("domain_allowlist.update.error", scope: "decidim.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members.rb b/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members.rb index 4d0e713998dd4..c3ddbe8234f9b 100644 --- a/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members.rb +++ b/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members.rb @@ -15,6 +15,7 @@ module HasMembers included do include Decidim::Admin::ParticipatorySpace::Concerns::MembersFilterable + helper PaginateHelper helper_method :members @@ -52,7 +53,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("members.update.error", scope: "decidim.admin") - render template: "decidim/admin/members/edit", status: :unprocessable_entity + render template: "decidim/admin/members/edit", status: :unprocessable_content end end end @@ -69,7 +70,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("members.create.error", scope: "decidim.admin") - render template: "decidim/admin/members/new", status: :unprocessable_entity + render template: "decidim/admin/members/new", status: :unprocessable_content end end end @@ -85,7 +86,7 @@ def destroy on(:invalid) do flash.now[:alert] = I18n.t("members.destroy.error", scope: "decidim.admin") - render template: "decidim/admin/members/index", status: :unprocessable_entity + render template: "decidim/admin/members/index", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members_csv_import.rb b/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members_csv_import.rb index f8e2e45f0bdb5..ac30472cabccf 100644 --- a/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members_csv_import.rb +++ b/decidim-admin/app/controllers/decidim/admin/participatory_space/concerns/has_members_csv_import.rb @@ -35,7 +35,7 @@ def create on(:invalid) do flash[:alert] = I18n.t("members_csv_imports.create.invalid", scope: "decidim.admin") - render template: "decidim/admin/members_csv_imports/new", status: :unprocessable_entity + render template: "decidim/admin/members_csv_imports/new", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/participatory_space/user_role_controller.rb b/decidim-admin/app/controllers/decidim/admin/participatory_space/user_role_controller.rb index 2f0f0d368e06b..cf88119cc0db3 100644 --- a/decidim-admin/app/controllers/decidim/admin/participatory_space/user_role_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/participatory_space/user_role_controller.rb @@ -38,7 +38,7 @@ def create on(:invalid) do flash[:alert] = I18n.t("create.error", scope: i18n_scope) - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -56,7 +56,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("update.error", scope: i18n_scope) - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/reminders_controller.rb b/decidim-admin/app/controllers/decidim/admin/reminders_controller.rb index d6ef2f64d413e..621eac3f42f73 100644 --- a/decidim-admin/app/controllers/decidim/admin/reminders_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/reminders_controller.rb @@ -27,7 +27,7 @@ def create on(:invalid) do flash.now[:alert] = t("decidim.admin.reminders.create.error") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/resource_permissions_controller.rb b/decidim-admin/app/controllers/decidim/admin/resource_permissions_controller.rb index 4c7c876082d3f..21da15bb3aa09 100644 --- a/decidim-admin/app/controllers/decidim/admin/resource_permissions_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/resource_permissions_controller.rb @@ -25,7 +25,7 @@ def update end on(:invalid) do - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/scope_types_controller.rb b/decidim-admin/app/controllers/decidim/admin/scope_types_controller.rb index 8ad8270a73dae..6d4f17c3c5d89 100644 --- a/decidim-admin/app/controllers/decidim/admin/scope_types_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/scope_types_controller.rb @@ -34,7 +34,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("scope_types.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -56,7 +56,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("scope_types.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/scopes_controller.rb b/decidim-admin/app/controllers/decidim/admin/scopes_controller.rb index 635a3f5a0cf9b..efbfa38744a6b 100644 --- a/decidim-admin/app/controllers/decidim/admin/scopes_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/scopes_controller.rb @@ -6,6 +6,7 @@ module Admin # class ScopesController < Decidim::Admin::ApplicationController include Decidim::Admin::Concerns::HasTabbedMenu + helper Decidim::Admin::ScopesHelper layout "decidim/admin/settings" @@ -36,7 +37,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("scopes.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -58,7 +59,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("scopes.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/share_tokens_controller.rb b/decidim-admin/app/controllers/decidim/admin/share_tokens_controller.rb index 8f3b8c4b2d990..e2f152a259094 100644 --- a/decidim-admin/app/controllers/decidim/admin/share_tokens_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/share_tokens_controller.rb @@ -31,7 +31,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("share_tokens.create.invalid", scope: "decidim.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -53,7 +53,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("share_tokens.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/space_publications_controller.rb b/decidim-admin/app/controllers/decidim/admin/space_publications_controller.rb index eefb3c10e4f8f..6a669affdbd18 100644 --- a/decidim-admin/app/controllers/decidim/admin/space_publications_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/space_publications_controller.rb @@ -17,7 +17,7 @@ def create flash.now[:alert] = I18n.t("create.error", scope: i18n_scope) end - redirect_back(fallback_location:) + redirect_back_or_to(fallback_location) end end @@ -33,7 +33,7 @@ def destroy flash.now[:alert] = I18n.t("destroy.error", scope: i18n_scope) end - redirect_back(fallback_location:) + redirect_back_or_to(fallback_location) end end diff --git a/decidim-admin/app/controllers/decidim/admin/static_page_topics_controller.rb b/decidim-admin/app/controllers/decidim/admin/static_page_topics_controller.rb index d9b7557864be4..a61a77004f14a 100644 --- a/decidim-admin/app/controllers/decidim/admin/static_page_topics_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/static_page_topics_controller.rb @@ -30,7 +30,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("static_page_topics.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -52,7 +52,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("static_page_topics.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/static_pages_controller.rb b/decidim-admin/app/controllers/decidim/admin/static_pages_controller.rb index eac4dca23ebd0..007369100921e 100644 --- a/decidim-admin/app/controllers/decidim/admin/static_pages_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/static_pages_controller.rb @@ -62,7 +62,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("static_pages.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -85,7 +85,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("static_pages.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/taxonomies_controller.rb b/decidim-admin/app/controllers/decidim/admin/taxonomies_controller.rb index a4451b9f4dbfc..792847558b8bf 100644 --- a/decidim-admin/app/controllers/decidim/admin/taxonomies_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/taxonomies_controller.rb @@ -39,7 +39,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("create.invalid", scope: "decidim.admin.taxonomies") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -66,7 +66,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.admin.taxonomies") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end @@ -83,7 +83,7 @@ def destroy flash.now[:alert] = I18n.t("destroy.invalid", scope: "decidim.admin.taxonomies") end end - redirect_back(fallback_location: taxonomies_path) + redirect_back_or_to(taxonomies_path) end def reorder diff --git a/decidim-admin/app/controllers/decidim/admin/taxonomy_filters_controller.rb b/decidim-admin/app/controllers/decidim/admin/taxonomy_filters_controller.rb index b69bf5b09b676..ac4ddb2391ee7 100644 --- a/decidim-admin/app/controllers/decidim/admin/taxonomy_filters_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/taxonomy_filters_controller.rb @@ -41,7 +41,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("create.error", scope: "decidim.admin.taxonomy_filters") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -63,7 +63,7 @@ def update end on(:invalid) do flash.now[:alert] = I18n.t("update.error", scope: "decidim.admin.taxonomy_filters") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end @@ -78,7 +78,7 @@ def destroy flash[:alert] = I18n.t("destroy.error", scope: "decidim.admin.taxonomy_filters") end end - redirect_back(fallback_location: decidim_admin.taxonomy_filters_path(root_taxonomy)) + redirect_back_or_to(decidim_admin.taxonomy_filters_path(root_taxonomy)) end private diff --git a/decidim-admin/app/controllers/decidim/admin/taxonomy_items_controller.rb b/decidim-admin/app/controllers/decidim/admin/taxonomy_items_controller.rb index 573c71f3bac1d..5696daac07940 100644 --- a/decidim-admin/app/controllers/decidim/admin/taxonomy_items_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/taxonomy_items_controller.rb @@ -9,7 +9,7 @@ class TaxonomyItemsController < Decidim::Admin::ApplicationController before_action do if taxonomy_item && taxonomy_item.parent_ids.exclude?(taxonomy.id) flash[:alert] = I18n.t("update.invalid", scope: "decidim.admin.taxonomies") - render plain: I18n.t("update.invalid", scope: "decidim.admin.taxonomies"), status: :unprocessable_entity + render plain: I18n.t("update.invalid", scope: "decidim.admin.taxonomies"), status: :unprocessable_content end end @@ -29,7 +29,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("create.invalid", scope: "decidim.admin.taxonomies") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -50,7 +50,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.admin.taxonomies") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-admin/app/controllers/decidim/admin/users_controller.rb b/decidim-admin/app/controllers/decidim/admin/users_controller.rb index 4146bf6d67137..47d234191024a 100644 --- a/decidim-admin/app/controllers/decidim/admin/users_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/users_controller.rb @@ -38,7 +38,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("users.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb b/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb index a0eacb5de4632..da3ff1c8ae269 100644 --- a/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb +++ b/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb @@ -5,6 +5,7 @@ module Admin # A form object to create or update areas. class TaxonomyFilterForm < Form include TranslatableAttributes + Item = Struct.new(:name, :value, :children) Manifest = Struct.new(:id, :name) diff --git a/decidim-admin/app/helpers/decidim/admin/settings_helper.rb b/decidim-admin/app/helpers/decidim/admin/settings_helper.rb index fcf8725e2a3ca..076d95d7811c6 100644 --- a/decidim-admin/app/helpers/decidim/admin/settings_helper.rb +++ b/decidim-admin/app/helpers/decidim/admin/settings_helper.rb @@ -108,7 +108,8 @@ def render_select_form_field(form, attribute, name, i18n_scope, options) html = form.select( name, choices, - { include_blank: attribute.include_blank, label: options[:label] } + { include_blank: attribute.include_blank, label: options[:label] }, + { disabled: options[:readonly] || false } ) html << content_tag(:p, options[:help_text], class: "help-text") if options[:help_text] html @@ -227,6 +228,8 @@ def integer_with_units(form, attribute, name, i18n_scope, options) # @param i18n_scope (see #settings_attribute_input) # @param [Object] form def taxonomy_filters(form, name, i18n_scope) + return disabled_taxonomy_filters(name, i18n_scope) if @component&.new_record? + current_filters = content_tag(:div, class: "js-current-filters") do render partial: "decidim/admin/taxonomy_filters_selector/component_table", locals: { field_name: "#{form.object_name}[#{name}][]", component: @component } @@ -250,6 +253,15 @@ def taxonomy_filters(form, name, i18n_scope) label_tag(name, t(name, scope: i18n_scope)) + container + drawer end + + def disabled_taxonomy_filters(name, i18n_scope) + container = content_tag(:div) do + message = t("taxonomy_filters_unavailable", scope: "decidim.components.settings.global") + content_tag(:p, message, class: "help-text") + end + + label_tag(name, t(name, scope: i18n_scope)) + container + end end end end diff --git a/decidim-admin/app/jobs/decidim/admin/newsletter_job.rb b/decidim-admin/app/jobs/decidim/admin/newsletter_job.rb index fda13b1410b60..28834cff4edd9 100644 --- a/decidim-admin/app/jobs/decidim/admin/newsletter_job.rb +++ b/decidim-admin/app/jobs/decidim/admin/newsletter_job.rb @@ -6,7 +6,7 @@ module Admin # class NewsletterJob < ApplicationJob queue_as :newsletter - self.enqueue_after_transaction_commit = :never + self.enqueue_after_transaction_commit = false def perform(newsletter, form, recipients_ids) @newsletter = newsletter diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/_datepicker.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/_datepicker.scss index b76d31889ed95..975500a8ba8a0 100644 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/_datepicker.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/_datepicker.scss @@ -22,10 +22,6 @@ @apply top-2; } - &__pick-calendar { - @apply z-[3]; - } - &__close-calendar { @apply z-[3]; } diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/_forms.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/_forms.scss index 177d7990713a9..4662dd50e3d61 100644 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/_forms.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/_forms.scss @@ -54,7 +54,6 @@ transition: all 0.2s ease; svg[role="img"] { - cursor: default !important; transition: color 0.2s ease; } diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/_sidebar-menu.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/_sidebar-menu.scss index 1680ab240534d..4db16bb3b817b 100644 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/_sidebar-menu.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/_sidebar-menu.scss @@ -4,7 +4,7 @@ &__item { a, &-disabled { - @apply gap-x-2 p-2 flex items-center text-sm truncate border border-gray-5 rounded; + @apply gap-x-2 p-2 flex items-center text-sm border border-gray-5 rounded; > svg { @apply w-4 h-4 flex-none text-gray fill-current; @@ -25,7 +25,11 @@ } & .component-counter { - @apply ml-auto inline-flex items-center justify-center w-5 h-5 text-xs font-semibold rounded-full bg-background-4 border-secondary; + @apply flex-shrink-0 ml-auto inline-flex items-center justify-center w-5 h-5 text-xs font-semibold rounded-full bg-background-4 border-secondary; + } + + a > span:first-child { + @apply min-w-0 whitespace-normal break-words; } ul { diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/_table-list.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/_table-list.scss index 1f4a3820de00f..6f3e3e703236d 100644 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/_table-list.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/_table-list.scss @@ -141,7 +141,7 @@ } .dragging-handle { - @apply cursor-ns-resize align-top p-3; + @apply cursor-grab align-top p-3; .dragger { @apply text-2xl; diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/_taxonomies.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/_taxonomies.scss index 170141d6365eb..d91cb4a52b95e 100644 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/_taxonomies.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/_taxonomies.scss @@ -14,7 +14,7 @@ } td { - @apply align-top cursor-ns-resize; + @apply align-top cursor-grab; &.js-drag-handle .dragger { @apply mt-1; diff --git a/decidim-admin/app/views/decidim/admin/admin_terms/show.html.erb b/decidim-admin/app/views/decidim/admin/admin_terms/show.html.erb index f6183f5ce914f..dd41c982b3f7b 100644 --- a/decidim-admin/app/views/decidim/admin/admin_terms/show.html.erb +++ b/decidim-admin/app/views/decidim/admin/admin_terms/show.html.erb @@ -1,8 +1,10 @@ +<% add_decidim_page_title(t(".title")) %> + <%= cell("decidim/announcement", announcement_body, callout_class: current_user.admin_terms_accepted? ? "success" : "warning" ) %>

- <%= t("title", scope: "decidim.admin.admin_terms_of_service") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/area_types/index.html.erb b/decidim-admin/app/views/decidim/admin/area_types/index.html.erb index 0d96f35a2becd..ccdbe9c1f6c2e 100644 --- a/decidim-admin/app/views/decidim/admin/area_types/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/area_types/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("decidim.admin.titles.area_types")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t "decidim.admin.titles.area_types" %> + <%= t(".title") %> <% if allowed_to? :create, :area_type %> <%= link_to t("actions.add", scope: "decidim.admin"), [:new, :area_type], class: "button button__sm button__secondary new" %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/areas/index.html.erb b/decidim-admin/app/views/decidim/admin/areas/index.html.erb index 2d16f0c61a4a9..8f9882e2dbab9 100644 --- a/decidim-admin/app/views/decidim/admin/areas/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/areas/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("areas", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t "decidim.admin.titles.areas" %> + <%= t ".title" %> <% if allowed_to? :create, :area %> <%= link_to t("actions.add", scope: "decidim.admin"), new_area_path, class: "button button__sm button__secondary new" %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/attachment_collections/edit.html.erb b/decidim-admin/app/views/decidim/admin/attachment_collections/edit.html.erb index 8a74bf61f6eba..32ec6003e1918 100644 --- a/decidim-admin/app/views/decidim/admin/attachment_collections/edit.html.erb +++ b/decidim-admin/app/views/decidim/admin/attachment_collections/edit.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("attachment_collections.edit.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("attachment_collections.edit.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb b/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb index 8a759b079324e..d8e70bea211e0 100644 --- a/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb @@ -1,9 +1,9 @@ -<% add_decidim_page_title(t("attachment_collections.index.attachment_collections_title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("attachment_collections.index.attachment_collections_title", scope: "decidim.admin") %> + <%= t(".title") %> <% if allowed_to? :create, :attachment_collection %> <%= link_to t("actions.attachment_collection.new", scope: "decidim.admin"), url_for(action: :new), class: "button button__sm button__secondary new" %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/attachment_collections/new.html.erb b/decidim-admin/app/views/decidim/admin/attachment_collections/new.html.erb index 67d609ef67b4c..1fb655c6e7b96 100644 --- a/decidim-admin/app/views/decidim/admin/attachment_collections/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/attachment_collections/new.html.erb @@ -1,7 +1,7 @@ -<% add_decidim_page_title(t("attachment_collections.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("attachment_collections.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/attachments/index.html.erb b/decidim-admin/app/views/decidim/admin/attachments/index.html.erb index 0852f9065557c..15273c22be758 100644 --- a/decidim-admin/app/views/decidim/admin/attachments/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/attachments/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t(".attachments_title")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t(".attachments_title") %> + <%= t(".title") %> <% if allowed_to? :create, :attachment %> <%= link_to t("actions.attachment.new", scope: "decidim.admin"), url_for(action: :new), class: "button button__sm button__secondary new" %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/authorization_workflows/index.html.erb b/decidim-admin/app/views/decidim/admin/authorization_workflows/index.html.erb index e1ec2474f0e12..934d7c2f40109 100644 --- a/decidim-admin/app/views/decidim/admin/authorization_workflows/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/authorization_workflows/index.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("authorization_workflows", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("authorization_workflows", scope: "decidim.admin.titles") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/block_user/new.html.erb b/decidim-admin/app/views/decidim/admin/block_user/new.html.erb index 086ab32ea54a7..e83213f7b8852 100644 --- a/decidim-admin/app/views/decidim/admin/block_user/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/block_user/new.html.erb @@ -1,4 +1,5 @@ <% add_decidim_page_title(t(".title", name: user.name)) %> +

<%= t(".title", name: user.name) %> diff --git a/decidim-admin/app/views/decidim/admin/components/index.html.erb b/decidim-admin/app/views/decidim/admin/components/index.html.erb index 8786950970980..4b41cdf758314 100644 --- a/decidim-admin/app/views/decidim/admin/components/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/components/index.html.erb @@ -1,9 +1,9 @@ -<% add_decidim_page_title(t("components.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("components.title", scope: "decidim.admin") %> + <%= t(".title") %> <% if allowed_to?(:create, :component) %>
diff --git a/decidim-admin/app/views/decidim/admin/components/manage_trash.html.erb b/decidim-admin/app/views/decidim/admin/components/manage_trash.html.erb index 9f57bccc47c3e..0b46cc872ac06 100644 --- a/decidim-admin/app/views/decidim/admin/components/manage_trash.html.erb +++ b/decidim-admin/app/views/decidim/admin/components/manage_trash.html.erb @@ -1,9 +1,9 @@ -<% add_decidim_page_title(t("components.manage_trash.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("components.manage_trash.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/conflicts/edit.html.erb b/decidim-admin/app/views/decidim/admin/conflicts/edit.html.erb index c66b11589e51f..a1c415ffdacb2 100644 --- a/decidim-admin/app/views/decidim/admin/conflicts/edit.html.erb +++ b/decidim-admin/app/views/decidim/admin/conflicts/edit.html.erb @@ -1,6 +1,8 @@ +<% add_decidim_page_title(t(".title")) %> +
-
Transfer User
+
<%= t(".title") %>
diff --git a/decidim-admin/app/views/decidim/admin/conflicts/index.html.erb b/decidim-admin/app/views/decidim/admin/conflicts/index.html.erb index 16117766de80e..392d6b569586b 100644 --- a/decidim-admin/app/views/decidim/admin/conflicts/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/conflicts/index.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("title", scope: "decidim.admin.conflicts")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("title", scope: "decidim.admin.conflicts") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/dashboard/show.html.erb b/decidim-admin/app/views/decidim/admin/dashboard/show.html.erb index 858a3445a11e8..b3a7ec5cc863f 100644 --- a/decidim-admin/app/views/decidim/admin/dashboard/show.html.erb +++ b/decidim-admin/app/views/decidim/admin/dashboard/show.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("decidim.admin.titles.dashboard")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t "decidim.admin.titles.dashboard" %> <%= current_organization_name %> + <%= t(".title") %> <%= current_organization_name %>

@@ -46,6 +46,6 @@ <% end %> <% if current_user.admin_terms_accepted? %> - <%= link_to( t("title", scope: "decidim.admin.admin_terms_of_service"), admin_terms_show_path, class: "button button__text-secondary") %> + <%= link_to( t("title", scope: "decidim.admin.admin_terms.show"), admin_terms_show_path, class: "button button__text-secondary") %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/devise/mailers/password_change.html.erb b/decidim-admin/app/views/decidim/admin/devise/mailers/password_change.html.erb deleted file mode 100644 index 77839a7a15cdf..0000000000000 --- a/decidim-admin/app/views/decidim/admin/devise/mailers/password_change.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -

Hello <%= @resource.email %>!

- -

We are contacting you to notify you that your password has been changed.

diff --git a/decidim-admin/app/views/decidim/admin/devise/mailers/reset_password_instructions.html.erb b/decidim-admin/app/views/decidim/admin/devise/mailers/reset_password_instructions.html.erb deleted file mode 100644 index 708edf07be4be..0000000000000 --- a/decidim-admin/app/views/decidim/admin/devise/mailers/reset_password_instructions.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -

Hello <%= @resource.email %>!

- -

Someone has requested a link to change your password. You can do this through the link below.

- -

<%= link_to "Change my password", edit_password_url(@resource, reset_password_token: @token) %>

- -

If you did not request this, please ignore this email.

-

Your password will not change until you access the link above and create a new one.

diff --git a/decidim-admin/app/views/decidim/admin/help_sections/update.html.erb b/decidim-admin/app/views/decidim/admin/help_sections/update.html.erb index 6e05cc045575a..31d11247ac7d7 100644 --- a/decidim-admin/app/views/decidim/admin/help_sections/update.html.erb +++ b/decidim-admin/app/views/decidim/admin/help_sections/update.html.erb @@ -1 +1,3 @@ +<% add_decidim_page_title(t(".title")) %> + <%= render partial: "form", object: @form %> diff --git a/decidim-admin/app/views/decidim/admin/impersonatable_users/index.html.erb b/decidim-admin/app/views/decidim/admin/impersonatable_users/index.html.erb index 2fab7a6d3c532..65649997871f4 100644 --- a/decidim-admin/app/views/decidim/admin/impersonatable_users/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/impersonatable_users/index.html.erb @@ -1,4 +1,5 @@ -<% add_decidim_page_title(t("impersonatable_users", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %> + <% if current_organization.available_authorizations.empty? %>
<%= cell("decidim/announcement", t(".needs_authorization_warning"), callout_class: "warning" ) %> @@ -7,7 +8,7 @@

- <%= t "decidim.admin.titles.impersonatable_users" %> + <%= t ".title" %> <% if allowed_to? :impersonate, :impersonatable_user, user: new_managed_user %> <%= link_to t(".impersonate_new_managed_user"), new_impersonatable_user_impersonation_path(:new_managed_user), class: "button button__sm button__secondary #{"disabled" if current_organization.available_authorizations.empty?}" %> <% end %> diff --git a/decidim-admin/app/views/decidim/admin/impersonations/new.html.erb b/decidim-admin/app/views/decidim/admin/impersonations/new.html.erb index cce55b1bec168..ebd237dbf6062 100644 --- a/decidim-admin/app/views/decidim/admin/impersonations/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/impersonations/new.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("impersonate_new_managed_user", scope: "decidim.admin.impersonations.new")) %> +<% add_decidim_page_title(t(".title")) %> +

<% if creating_managed_user? %> - <%= t(".impersonate_new_managed_user") %> + <%= t(".title") %> <% else %> <% if @form.user.managed? %> <%= t(".impersonate_existing_managed_user", name: @form.user.name) %> diff --git a/decidim-admin/app/views/decidim/admin/imports/new.html.erb b/decidim-admin/app/views/decidim/admin/imports/new.html.erb index bdf151be9c30f..14a53b52b2894 100644 --- a/decidim-admin/app/views/decidim/admin/imports/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/imports/new.html.erb @@ -1,4 +1,5 @@ <% add_decidim_page_title(import_manifest.message(:title, self)) %> +

<%= import_manifest.message(:title, self) %> diff --git a/decidim-admin/app/views/decidim/admin/logs/_logs_list.html.erb b/decidim-admin/app/views/decidim/admin/logs/_logs_list.html.erb index cbac48cb47b9e..d85d0543b147f 100644 --- a/decidim-admin/app/views/decidim/admin/logs/_logs_list.html.erb +++ b/decidim-admin/app/views/decidim/admin/logs/_logs_list.html.erb @@ -1,7 +1,7 @@

- <%= t "decidim.admin.titles.admin_log" %> + <%= t "decidim.admin.logs.index.title" %>

<%= render partial: "decidim/admin/logs/filters" if defined?(display_filters) && display_filters %> diff --git a/decidim-admin/app/views/decidim/admin/logs/index.html.erb b/decidim-admin/app/views/decidim/admin/logs/index.html.erb index b08e5fe4f8509..7af432ec8134f 100644 --- a/decidim-admin/app/views/decidim/admin/logs/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/logs/index.html.erb @@ -1,4 +1,4 @@ -<% add_decidim_page_title(t("admin_log", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %> <%= render partial: "decidim/admin/logs/logs_list", locals: { logs:, empty_logs: no_logs_available?, display_filters: true } %> <%= decidim_paginate logs %> diff --git a/decidim-admin/app/views/decidim/admin/managed_users/impersonation_logs/index.html.erb b/decidim-admin/app/views/decidim/admin/managed_users/impersonation_logs/index.html.erb index c1dfb56faae16..28a5487da2c1f 100644 --- a/decidim-admin/app/views/decidim/admin/managed_users/impersonation_logs/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/managed_users/impersonation_logs/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("decidim.admin.titles.impersonations")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t "decidim.admin.titles.impersonations" %> + <%= t ".title" %>

diff --git a/decidim-admin/app/views/decidim/admin/managed_users/promotions/new.html.erb b/decidim-admin/app/views/decidim/admin/managed_users/promotions/new.html.erb index c890a31d0ec2a..8df79d3c485e8 100644 --- a/decidim-admin/app/views/decidim/admin/managed_users/promotions/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/managed_users/promotions/new.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t(".new_managed_user_promotion")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t(".new_managed_user_promotion") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/newsletter_templates/show.html.erb b/decidim-admin/app/views/decidim/admin/newsletter_templates/show.html.erb index 66599d17432ae..23891cac94b7e 100644 --- a/decidim-admin/app/views/decidim/admin/newsletter_templates/show.html.erb +++ b/decidim-admin/app/views/decidim/admin/newsletter_templates/show.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t(".preview", template_name: t(template_manifest.public_name_key))) %> +<% add_decidim_page_title(t(".title", template_name: t(template_manifest.public_name_key))) %> +

- <%= t ".preview", template_name: t(template_manifest.public_name_key) %> + <%= t ".title", template_name: t(template_manifest.public_name_key) %>

diff --git a/decidim-admin/app/views/decidim/admin/newsletters/show.html.erb b/decidim-admin/app/views/decidim/admin/newsletters/show.html.erb index 362cdd1ffd248..ff6c3600f26aa 100644 --- a/decidim-admin/app/views/decidim/admin/newsletters/show.html.erb +++ b/decidim-admin/app/views/decidim/admin/newsletters/show.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t(".preview")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t ".preview" %> + <%= t ".title" %>

<% if allowed_to?(:update, :newsletter, newsletter: @newsletter) %> diff --git a/decidim-admin/app/views/decidim/admin/officializations/index.html.erb b/decidim-admin/app/views/decidim/admin/officializations/index.html.erb index a190d5bed569a..c1f179dbe0460 100644 --- a/decidim-admin/app/views/decidim/admin/officializations/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/officializations/index.html.erb @@ -1,8 +1,10 @@ -<% add_decidim_page_title(t("decidim.admin.titles.participants")) %> +<% add_decidim_page_title(t(".title")) %> -
+
-

<%= t "decidim.admin.titles.participants" %>

+

+ <%= t ".title" %> +

<%= admin_filter_selector %>
diff --git a/decidim-admin/app/views/decidim/admin/officializations/show_email.html.erb b/decidim-admin/app/views/decidim/admin/officializations/show_email.html.erb index 680203b3487fb..3c306de596edb 100644 --- a/decidim-admin/app/views/decidim/admin/officializations/show_email.html.erb +++ b/decidim-admin/app/views/decidim/admin/officializations/show_email.html.erb @@ -1 +1,3 @@ +<% add_decidim_page_title(t(".title")) %> + <%= link_to user.email, "mailto:#{user.email}" %> diff --git a/decidim-admin/app/views/decidim/admin/organization_external_domain_allowlist/edit.html.erb b/decidim-admin/app/views/decidim/admin/organization_external_domain_allowlist/edit.html.erb index 2ea4feeda353e..dc82f699dd6a0 100644 --- a/decidim-admin/app/views/decidim/admin/organization_external_domain_allowlist/edit.html.erb +++ b/decidim-admin/app/views/decidim/admin/organization_external_domain_allowlist/edit.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("edit_external_domains", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("title", scope: "decidim.admin.organization_external_domain_allowlist.form") %> + <%= t(".title") %>

diff --git a/decidim-admin/app/views/decidim/admin/reminders/new.html.erb b/decidim-admin/app/views/decidim/admin/reminders/new.html.erb index c6cee2d5210a3..63ab9ef2ce1ee 100644 --- a/decidim-admin/app/views/decidim/admin/reminders/new.html.erb +++ b/decidim-admin/app/views/decidim/admin/reminders/new.html.erb @@ -1,4 +1,11 @@ -
+<% add_decidim_page_title(t(".title")) %> + +
+
+

+ <%= t ".title" %> +

+
<%= decidim_form_for(@form, html: { class: "form form-defaults new_order_reminder" }, url: component_reminders_path(name: reminder_manifest.name), class: "form grid-container") do |form| %>
diff --git a/decidim-admin/app/views/decidim/admin/scope_types/index.html.erb b/decidim-admin/app/views/decidim/admin/scope_types/index.html.erb index 4a789ab31623c..d34ec4631dddb 100644 --- a/decidim-admin/app/views/decidim/admin/scope_types/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/scope_types/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("decidim.admin.titles.scope_types")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t "decidim.admin.titles.scope_types" %> + <%= t ".title" %> <% if allowed_to? :create, :scope_type %> <%= link_to t("actions.add", scope: "decidim.admin"), [:new, :scope_type], class: "button button__sm button__secondary new" %> diff --git a/decidim-admin/app/views/decidim/admin/scopes/index.html.erb b/decidim-admin/app/views/decidim/admin/scopes/index.html.erb index 7730666b48870..6e3f35dd52160 100644 --- a/decidim-admin/app/views/decidim/admin/scopes/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/scopes/index.html.erb @@ -1,11 +1,11 @@ -<% add_decidim_page_title(t("decidim.admin.titles.scopes")) %> +<% add_decidim_page_title(t(".title")) %>

<% if parent_scope %> <%= scope_breadcrumbs(parent_scope).join(" - ").html_safe %> <%= link_to t("actions.add", scope: "decidim.admin"), new_scope_scope_path(parent_scope), class: "button button__sm button__secondary" if allowed_to? :create, :scope %><%= link_to t("actions.edit", scope: "decidim.admin"), edit_scope_path(parent_scope), class: "button button__sm button__secondary" if allowed_to? :edit, :scope, scope: parent_scope %> <% else %> - <%= t "decidim.admin.titles.scopes" %> <%= link_to t("actions.add", scope: "decidim.admin"), new_scope_path, class: "button button__sm button__secondary" if allowed_to? :create, :scope %> + <%= t ".title" %> <%= link_to t("actions.add", scope: "decidim.admin"), new_scope_path, class: "button button__sm button__secondary" if allowed_to? :create, :scope %> <% end %>

diff --git a/decidim-admin/app/views/decidim/admin/share_tokens/index.html.erb b/decidim-admin/app/views/decidim/admin/share_tokens/index.html.erb index e0b5e3b720961..4e498e12c866f 100644 --- a/decidim-admin/app/views/decidim/admin/share_tokens/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/share_tokens/index.html.erb @@ -1,3 +1,5 @@ +<% add_decidim_page_title(t(".title", name: resource_title)) %> +

- - - <% abbr_day_names.each_with_index do |day, i| %> - - <% end %> - - - <% weeks.each do |days| %> - - <% is_first_day = first_day_of_month?(days.first) %> - - <% if is_first_day %> - <% (7 - days.length).times do %> - - <% end %> - <% end %> - - <% days.each do |day| %> - <%= content_tag :td, class: day_class(day) do %> - - <% end %> - <% end %> - - <% if !is_first_day %> - <% (7 - days.length).times do %> - - <% end %> - <% end %> - - <% end %> - -
<%= month_name %>
<%= day %>
diff --git a/decidim-meetings/app/cells/decidim/meetings/question_responses_cell.rb b/decidim-meetings/app/cells/decidim/meetings/question_responses_cell.rb index 0daf3ae012b06..9af17cb018d3a 100644 --- a/decidim-meetings/app/cells/decidim/meetings/question_responses_cell.rb +++ b/decidim-meetings/app/cells/decidim/meetings/question_responses_cell.rb @@ -22,7 +22,7 @@ def response_options_with_percentages # # This calculation is a bit complex because of multiple option responses question_responses_choices = Decidim::Meetings::ResponseOption.where(decidim_question_id: model.id) - .joins([choices: :response]) + .joins([{ choices: :response }]) .group(Arel.sql("#{responses_table_name}.id, #{response_options_table_name}.id")) .select(<<~SELECT #{response_options_table_name}.id AS id, diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/agenda_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/agenda_controller.rb index 3e086b6b2e2d3..ae489ff323ba5 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/agenda_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/agenda_controller.rb @@ -27,7 +27,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("agenda.create.invalid", scope: "decidim.meetings.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -51,7 +51,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("agenda.update.invalid", scope: "decidim.meetings.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/invites_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/invites_controller.rb index ea55f8e813bf0..db44c6ed7643c 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/invites_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/invites_controller.rb @@ -30,7 +30,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("invites.create.error", scope: "decidim.meetings.admin") - render :index, status: :unprocessable_entity + render :index, status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb index fb5dd291f3ef7..b2f7f5245443b 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb @@ -26,7 +26,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("meetings.close.invalid", scope: "decidim.meetings.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb index acb8fab2f2777..a81b5b893b350 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb @@ -27,7 +27,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("meeting_copies.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_controller.rb index 2640f94939c99..1662d896d7131 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_controller.rb @@ -29,7 +29,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("meetings.create.invalid", scope: "decidim.meetings.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -53,7 +53,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("meetings.update.invalid", scope: "decidim.meetings.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end @@ -69,7 +69,7 @@ def publish on(:invalid) do flash.now[:alert] = I18n.t("meetings.publish.invalid", scope: "decidim.meetings.admin") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end @@ -85,7 +85,7 @@ def unpublish on(:invalid) do flash.now[:alert] = I18n.t("meetings.unpublish.invalid", scope: "decidim.meetings.admin") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb index 3760692bc52e3..50152b0c517ba 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb @@ -47,7 +47,7 @@ def update on(:invalid) do # i18n-tasks-use t("decidim.forms.admin.questionnaires.update.invalid") flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.meetings.admin.meetings_poll") - render template: "decidim/meetings/admin/poll/edit", status: :unprocessable_entity + render template: "decidim/meetings/admin/poll/edit", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_attendees_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_attendees_controller.rb index f2947cb6545b3..39fcbb4297b27 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_attendees_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_attendees_controller.rb @@ -43,7 +43,7 @@ def validate_registration_code on(:invalid) do flash.now[:alert] = I18n.t("registrations_attendees.validate_registration_code.invalid", scope: "decidim.meetings.admin") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end @@ -59,7 +59,7 @@ def mark_as_attendee on(:invalid) do flash.now[:alert] = I18n.t("registrations_attendees.mark_attendee.invalid", scope: "decidim.meetings.admin") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_controller.rb index 12174e5a6c520..48d0c86334b3c 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/admin/registrations_controller.rb @@ -24,7 +24,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("registrations.update.invalid", scope: "decidim.meetings.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/meeting_closes_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/meeting_closes_controller.rb index 68496748ab636..20c00d1b061ed 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/meeting_closes_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/meeting_closes_controller.rb @@ -27,7 +27,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("meetings.close.invalid", scope: "decidim.meetings.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb index c4aba9cc86083..2ee739a419461 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb @@ -41,7 +41,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("meetings.create.invalid", scope: "decidim.meetings") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -88,7 +88,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("meetings.update.invalid", scope: "decidim.meetings") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/polls/responses_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/polls/responses_controller.rb index 2f4ecbae7770a..c26570de0f629 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/polls/responses_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/polls/responses_controller.rb @@ -37,7 +37,7 @@ def question end def response_params - params.require(:response).permit(:question_id, choices: [:body, :response_option_id]) + params.expect(response: [:question_id, { choices: [[:body, :response_option_id]] }]) end end end diff --git a/decidim-meetings/app/controllers/decidim/meetings/registrations_controller.rb b/decidim-meetings/app/controllers/decidim/meetings/registrations_controller.rb index bdac1ff695c3b..0395701590b44 100644 --- a/decidim-meetings/app/controllers/decidim/meetings/registrations_controller.rb +++ b/decidim-meetings/app/controllers/decidim/meetings/registrations_controller.rb @@ -22,12 +22,12 @@ def respond on(:invalid) do flash.now[:alert] = I18n.t(joining_waitlist ? "registrations.waitlist.invalid" : "registrations.create.invalid", scope: "decidim.meetings") - render template: "decidim/forms/questionnaires/show", status: :unprocessable_entity + render template: "decidim/forms/questionnaires/show", status: :unprocessable_content end on(:invalid_form) do flash.now[:alert] = I18n.t("response.invalid", scope: i18n_flashes_scope) - render template: "decidim/forms/questionnaires/show", status: :unprocessable_entity + render template: "decidim/forms/questionnaires/show", status: :unprocessable_content end end end diff --git a/decidim-meetings/app/helpers/decidim/meetings/application_helper.rb b/decidim-meetings/app/helpers/decidim/meetings/application_helper.rb index a673cba976f57..f99a0c2bed224 100644 --- a/decidim-meetings/app/helpers/decidim/meetings/application_helper.rb +++ b/decidim-meetings/app/helpers/decidim/meetings/application_helper.rb @@ -103,7 +103,7 @@ def activity_filter_values # If the meeting is official or the rich text editor is enabled on the # frontend, the meeting body is considered as safe content; that is unless - # the meeting comes from a collaborative_draft or a participatory_text. + # the meeting comes from a participatory_text. def safe_content? rich_text_editor_in_public_views? || safe_content_admin? end diff --git a/decidim-meetings/app/models/decidim/meetings/response.rb b/decidim-meetings/app/models/decidim/meetings/response.rb index 8f85840224cac..68a4500b8b4ba 100644 --- a/decidim-meetings/app/models/decidim/meetings/response.rb +++ b/decidim-meetings/app/models/decidim/meetings/response.rb @@ -28,7 +28,7 @@ def self.export_serializer end def organization - user.organization if user.present? + user.presence&.organization questionnaire&.questionnaire_for.try(:organization) end diff --git a/decidim-meetings/app/packs/stylesheets/decidim/meetings/_item.scss b/decidim-meetings/app/packs/stylesheets/decidim/meetings/_item.scss index 4b79ecbc454cd..f879442191745 100644 --- a/decidim-meetings/app/packs/stylesheets/decidim/meetings/_item.scss +++ b/decidim-meetings/app/packs/stylesheets/decidim/meetings/_item.scss @@ -35,11 +35,11 @@ &-month, &-day, &-year { - @apply inline-flex items-center justify-evenly empty:[&>p]:hidden; + @apply inline-flex items-center justify-center empty:[&>span]:hidden; } &-separator { - @apply mx-2 font-normal text-sm; + @apply mx-4 font-normal text-sm; } &__lg { diff --git a/decidim-meetings/app/serializers/decidim/meetings/registration_serializer.rb b/decidim-meetings/app/serializers/decidim/meetings/registration_serializer.rb index 2cdae411418c8..0fd6447761819 100644 --- a/decidim-meetings/app/serializers/decidim/meetings/registration_serializer.rb +++ b/decidim-meetings/app/serializers/decidim/meetings/registration_serializer.rb @@ -4,6 +4,7 @@ module Decidim module Meetings class RegistrationSerializer < Decidim::Exporters::Serializer include Decidim::TranslationsHelper + # Serializes a registration def serialize { diff --git a/decidim-meetings/app/views/decidim/meetings/admin/invites/index.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/invites/index.html.erb index f1867fe1ba9a0..373f1389365a9 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/invites/index.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/invites/index.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t(".invite_attendee")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t(".invite_attendee") %> + <%= t(".title") %>

diff --git a/decidim-meetings/app/views/decidim/meetings/admin/meeting_copies/new.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/meeting_copies/new.html.erb index aebad9db22a59..bf667645c6b37 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/meeting_copies/new.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/meeting_copies/new.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("meeting_copies.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("meeting_copies.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-meetings/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb index 7d1a58b7100b2..88b052cfe7d4c 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb @@ -3,7 +3,7 @@ "> <% if allowed_to? :update, :meeting, meeting: meeting %> - <%= link_to present(meeting).title(html_escape: true), edit_meeting_path(meeting) %> + <%= link_to present(meeting).title(html_escape: true), Decidim::ResourceLocatorPresenter.new(meeting).edit %> <% else %> <%= present(meeting).title(html_escape: true) %>
<% end %> @@ -42,7 +42,7 @@ "> <% if is_linked %> - <%= t("index.linked_meeting_warning_html", href: edit_meeting_path(meeting), name: present(meeting).space_title, scope: "decidim.meetings.admin.meetings") %> + <%= t("index.linked_meeting_warning_html", href: Decidim::ResourceLocatorPresenter.new(meeting).edit, name: present(meeting).space_title, scope: "decidim.meetings.admin.meetings") %> <% else %> <%= render partial: "decidim/meetings/admin/meetings/meeting_actions", locals: { meeting:, view: } %> <% end %> diff --git a/decidim-meetings/app/views/decidim/meetings/admin/poll/_question.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/poll/_question.html.erb index a613741df50b5..95d61868e8317 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/poll/_question.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/poll/_question.html.erb @@ -25,7 +25,7 @@ <% if editable %> - <% end %> diff --git a/decidim-meetings/app/views/decidim/meetings/admin/poll/edit.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/poll/edit.html.erb index b170e797ee70f..fac7f5d69b332 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/poll/edit.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/poll/edit.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(edit_questionnaire_title) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= edit_questionnaire_title %> + <%= t(".title") %> <% if questionnaire.responses.any? %>
<%= export_dropdown(current_component, questionnaire.id) if allowed_to?(:export_responses, :questionnaire) %> diff --git a/decidim-meetings/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb index 9f5f0800de97e..db9ff682a71f7 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb @@ -1,4 +1,4 @@ -<% add_decidim_page_title(t("decidim.forms.admin.questionnaires.edit_questions.title")) %> +<% add_decidim_page_title(t(".title")) %> <% if templates_defined? && choose_template? %> <%= render partial: "decidim/templates/admin/questionnaire_templates/choose", locals: { target: questionnaire, form_title: t("decidim.forms.admin.questionnaires.edit.title"), show_buttons: true } %> diff --git a/decidim-meetings/app/views/decidim/meetings/admin/registrations/edit.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/registrations/edit.html.erb index e91a21266d7d4..c0884aeb7e85f 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/registrations/edit.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/registrations/edit.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("title", scope: "decidim.meetings.admin.registrations.form")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("title", scope: "decidim.meetings.admin.registrations.form") %> + <%= t(".title") %>
<%= link_to t("registrations", scope: "decidim.meetings.admin.registrations.form"), meeting_registrations_attendees_path(meeting), class: "button button__sm button__transparent-secondary #{"disabled" unless allowed_to? :read_invites, :meeting, meeting: meeting}" %> <%= link_to t("invites", scope: "decidim.meetings.admin.registrations.form"), meeting_registrations_invites_path(meeting), class: "button button__sm button__transparent-secondary #{"disabled" unless allowed_to? :read_invites, :meeting, meeting: meeting}" %> diff --git a/decidim-meetings/app/views/decidim/meetings/admin/registrations_attendees/index.html.erb b/decidim-meetings/app/views/decidim/meetings/admin/registrations_attendees/index.html.erb index b8684aa640292..e9aeb6d954d99 100644 --- a/decidim-meetings/app/views/decidim/meetings/admin/registrations_attendees/index.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/admin/registrations_attendees/index.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("title", scope: "decidim.meetings.admin.registrations_attendees.index")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("title", scope: "decidim.meetings.admin.registrations_attendees.index") %> + <%= t(".title") %>
<%= link_to t("invites", scope: "decidim.meetings.admin.registrations.form"), meeting_registrations_invites_path(meeting), class: "button button__sm button__transparent-secondary #{"disabled" unless allowed_to? :read_invites, :meeting, meeting: meeting}" %> diff --git a/decidim-meetings/app/views/decidim/meetings/meetings/_meeting.html.erb b/decidim-meetings/app/views/decidim/meetings/meetings/_meeting.html.erb index 5e22c92bbbfdd..4ab5b2fc3be3b 100644 --- a/decidim-meetings/app/views/decidim/meetings/meetings/_meeting.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/meetings/_meeting.html.erb @@ -55,14 +55,14 @@ <% end %> - <%= cell "decidim/tab_panels", tab_panel_items %> - <% if meeting.agenda.present? && meeting.agenda.visible? %>
<%= render "meeting_agenda" %>
<% end %> + <%= cell "decidim/tab_panels", tab_panel_items %> + <% if meeting.closed? && meeting.closing_visible? %>
<%= render "meeting_minutes" %> diff --git a/decidim-meetings/app/views/decidim/meetings/shared/_meetings.html.erb b/decidim-meetings/app/views/decidim/meetings/shared/_meetings.html.erb index bda31717d73ef..b9fcba922bf9a 100644 --- a/decidim-meetings/app/views/decidim/meetings/shared/_meetings.html.erb +++ b/decidim-meetings/app/views/decidim/meetings/shared/_meetings.html.erb @@ -17,7 +17,7 @@
<% meetings.each do |meeting| %> - <%= card_for meeting %> + <%= card_for meeting, context: { show_space: component.blank? } %> <% end %>
diff --git a/decidim-meetings/config/locales/en.yml b/decidim-meetings/config/locales/en.yml index 96853a098f7fd..b8a6550a20adb 100644 --- a/decidim-meetings/config/locales/en.yml +++ b/decidim-meetings/config/locales/en.yml @@ -146,7 +146,6 @@ en: success: Meeting successfully duplicated. new: copy: Copy - title: Duplicate meeting tooltips: cannot_close_meetings: Cannot close this meeting as it is created by a participant cannot_duplicate_meetings: Cannot duplicate this meeting as it is created by a participant @@ -355,13 +354,16 @@ en: non_user: Non existing participant select_user: Select participant index: - invite_attendee: Invite attendee invites: Invites registrations_disabled: You cannot invite an attendee because the registrations are disabled. + title: Invite attendee meeting_closes: edit: close: Close title: Close meeting + meeting_copies: + new: + title: Duplicate meeting meetings: close: invalid: There was a problem closing this meeting. @@ -438,15 +440,21 @@ en: invalid: There was a problem updating this meeting poll. success: Meeting poll successfully updated. poll: + edit: + title: Edit poll form: announcement_html: - When a question receives responses or is published/closed, it can no longer be edited. - You can add a question at any time. - The poll will be closed when the results of all created questions have been published. - Visit the poll administration page to send questions and publish results. + registration_form: + edit_questions: + title: Edit questions registrations: edit: save: Save + title: Registrations form: available_slots_help: Leave it to 0 if you have unlimited slots available. invites: Invitations @@ -460,7 +468,6 @@ en: other: There has been %{count} registrations. reserved_slots_help: Leave it to 0 if you do not have reserved slots. reserved_slots_less_than: Must be less than or equal to %{count} - title: Registrations update: invalid: There was a problem saving the registration settings. success: Meeting registrations settings successfully saved. diff --git a/decidim-meetings/db/migrate/20180809134748_add_upcoming_events_as_content_block.rb b/decidim-meetings/db/migrate/20180809134748_add_upcoming_events_as_content_block.rb index 4c171f64597be..30ca2cccd4024 100644 --- a/decidim-meetings/db/migrate/20180809134748_add_upcoming_events_as_content_block.rb +++ b/decidim-meetings/db/migrate/20180809134748_add_upcoming_events_as_content_block.rb @@ -13,7 +13,7 @@ def change Organization.find_each do |organization| next if ContentBlock.where(decidim_organization_id: organization.id).exists?(manifest_name: "upcoming_events") - last_weight = ContentBlock.where(decidim_organization_id: organization.id).order("weight DESC").limit(1).pluck(:weight).last.to_i + last_weight = ContentBlock.where(decidim_organization_id: organization.id).order(weight: :desc).limit(1).pluck(:weight).last.to_i ContentBlock.create!( decidim_organization_id: organization.id, diff --git a/decidim-meetings/lib/decidim/api/linked_resources_interface.rb b/decidim-meetings/lib/decidim/api/linked_resources_interface.rb index b8a00daf4bcf1..b985bef6395f3 100644 --- a/decidim-meetings/lib/decidim/api/linked_resources_interface.rb +++ b/decidim-meetings/lib/decidim/api/linked_resources_interface.rb @@ -5,6 +5,7 @@ module Meetings # This interface represents all linked resources available in the module meetings module LinkedResourcesInterface include Decidim::Api::Types::BaseInterface + graphql_name "MeetingsLinkedResourcesInterface" description "An interface that can be used with Resourceable models." diff --git a/decidim-meetings/lib/decidim/api/services_interface.rb b/decidim-meetings/lib/decidim/api/services_interface.rb index 756c8e660159b..dff8b7ccc02dd 100644 --- a/decidim-meetings/lib/decidim/api/services_interface.rb +++ b/decidim-meetings/lib/decidim/api/services_interface.rb @@ -5,6 +5,7 @@ module Meetings # This interface represents a categorizable object. module ServicesInterface include Decidim::Api::Types::BaseInterface + description "An interface that can be used with services." field :services, [Decidim::Meetings::ServiceType, { null: true }], "The object's services", null: false diff --git a/decidim-meetings/lib/decidim/meetings.rb b/decidim-meetings/lib/decidim/meetings.rb index 70cb31297b36e..8431be49a1e12 100644 --- a/decidim-meetings/lib/decidim/meetings.rb +++ b/decidim-meetings/lib/decidim/meetings.rb @@ -17,20 +17,20 @@ module Meetings autoload :UserResponsesSerializer, "decidim/meetings/user_responses_serializer" autoload :SchemaOrgEventMeetingSerializer, "decidim/meetings/schema_org_event_meeting_serializer" - include ActiveSupport::Configurable + class << self + def config = self - # Public Setting that defines the interval when the upcoming meeting will be sent - config_accessor :upcoming_meeting_notification do - Decidim::Env.new("MEETINGS_UPCOMING_MEETING_NOTIFICATION", 2).to_i.days + def configure + yield self + end end - config_accessor :embeddable_services do - Decidim::Env.new("MEETINGS_EMBEDDABLE_SERVICES", "www.youtube.com www.twitch.tv meet.jit.si").to_array(separator: " ") - end + # Public Setting that defines the interval when the upcoming meeting will be sent + mattr_accessor :upcoming_meeting_notification, default: Decidim::Env.new("MEETINGS_UPCOMING_MEETING_NOTIFICATION", 2).to_i.days - config_accessor :waiting_list_enabled do - Decidim::Env.new("MEETINGS_WAITING_LIST_ENABLED", true).present? - end + mattr_accessor :embeddable_services, default: Decidim::Env.new("MEETINGS_EMBEDDABLE_SERVICES", "www.youtube.com www.twitch.tv meet.jit.si").to_array(separator: " ") + + mattr_accessor :waiting_list_enabled, default: Decidim::Env.new("MEETINGS_WAITING_LIST_ENABLED", true).present? end module ContentParsers diff --git a/decidim-meetings/lib/decidim/meetings/engine.rb b/decidim-meetings/lib/decidim/meetings/engine.rb index f90965d9f82d9..ed28a466f8916 100644 --- a/decidim-meetings/lib/decidim/meetings/engine.rb +++ b/decidim-meetings/lib/decidim/meetings/engine.rb @@ -13,7 +13,7 @@ class Engine < ::Rails::Engine isolate_namespace Decidim::Meetings routes do - resources :meetings, only: [:index, :show, :new, :create, :edit, :update, :withdraw] do + resources :meetings, only: [:index, :show, :new, :create, :edit, :update] do member do put :withdraw end diff --git a/decidim-meetings/spec/cells/decidim/meetings/content_blocks/highlighted_meetings_cell_spec.rb b/decidim-meetings/spec/cells/decidim/meetings/content_blocks/highlighted_meetings_cell_spec.rb index 4b979c3381ad8..e5f2c706d7564 100644 --- a/decidim-meetings/spec/cells/decidim/meetings/content_blocks/highlighted_meetings_cell_spec.rb +++ b/decidim-meetings/spec/cells/decidim/meetings/content_blocks/highlighted_meetings_cell_spec.rb @@ -48,6 +48,10 @@ module ContentBlocks it { expect(meetings_ids).to include(item_id(second_meeting)) } it { expect(meetings_ids).not_to include(item_id(unpublished_meeting)) } + it "shows the participatory space on homepage" do + expect(html).to have_content(decidim_escape_translated(meeting.component.participatory_space.title)) + end + it "orders them correctly" do expect(meetings_ids.length).to eq(2) expect(meetings_ids.first).to eq(item_id(meeting)) @@ -127,20 +131,12 @@ module ContentBlocks end context "with upcoming meetings in other month" do - context "when there are meetings in this month" do - context "and there are meetings in the next month" do - let!(:next_month_meeting) { create(:meeting, :published, component: meeting.component, start_time: meeting.start_time.advance(months: 1)) } - - it "renders the two months" do - expect(html).to have_css(".meeting-calendar__month time", count: 61) - end - end + let!(:second_meeting) do + create(:meeting, :published, start_time: 1.month.from_now, component: meeting.component) + end - context "and there are no meetings in the next month" do - it "renders only the current month" do - expect(html).to have_css(".meeting-calendar__month time", count: 31) - end - end + it "renders the meetings" do + expect(html).to have_css(".card__list", count: 2) end end end diff --git a/decidim-meetings/spec/cells/decidim/meetings/dates_and_map_cell_spec.rb b/decidim-meetings/spec/cells/decidim/meetings/dates_and_map_cell_spec.rb new file mode 100644 index 0000000000000..d004677644f2d --- /dev/null +++ b/decidim-meetings/spec/cells/decidim/meetings/dates_and_map_cell_spec.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim::Meetings + describe DatesAndMapCell, type: :cell do + controller Decidim::Meetings::MeetingsController + + subject { my_cell.call } + + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 4, 5, 0), end_time: Time.new(2020, 10, 15, 12, 0, 0, 0)) } + let(:my_cell) { cell("decidim/meetings/dates_and_map", meeting) } + + context "when rendering" do + it "renders the calendar container" do + expect(subject).to have_css(".meeting__calendar-container") + end + + it "shows the start time's month" do + expect(subject).to have_css(".meeting__calendar-month", text: "October") + end + + it "shows the start time's day" do + expect(subject).to have_css(".meeting__calendar-day", text: "15") + end + + it "shows the start time's year" do + expect(subject).to have_css(".meeting__calendar-year", text: "2020") + end + + it "does not show separator" do + expect(subject).to have_no_css(".meeting__calendar-separator") + end + end + + context "when meeting spans multiple days in the same month" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: Time.new(2020, 10, 17, 12, 0, 0, 0)) } + + it "shows the start day" do + expect(subject).to have_css(".meeting__calendar-day", text: "15") + end + + it "shows the end day" do + expect(subject).to have_css(".meeting__calendar-day", text: "17") + end + + it "shows the separator" do + expect(subject).to have_css(".meeting__calendar-separator") + end + end + + context "when meeting spans multiple months" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: Time.new(2020, 11, 17, 12, 0, 0, 0)) } + + it "shows the start month" do + expect(subject).to have_css(".meeting__calendar-month", text: "Oct") + end + + it "shows the end month" do + expect(subject).to have_css(".meeting__calendar-month", text: "Nov") + end + + it "shows the start day" do + expect(subject).to have_css(".meeting__calendar-day", text: "15") + end + + it "shows the end day" do + expect(subject).to have_css(".meeting__calendar-day", text: "17") + end + + it "shows month separator" do + expect(subject).to have_css(".meeting__calendar-separator") + end + end + + context "when meeting spans multiple years" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 12, 15, 10, 0, 0, 0), end_time: Time.new(2021, 1, 17, 12, 0, 0, 0)) } + + it "shows the start year" do + expect(subject).to have_css(".meeting__calendar-year", text: "2020") + end + + it "shows the end year" do + expect(subject).to have_css(".meeting__calendar-year", text: "2021") + end + + it "shows the separator" do + expect(subject).to have_css(".meeting__calendar-separator") + end + end + + context "when meeting spans same month and day across different years" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2024, 1, 15, 10, 0, 0, 0), end_time: Time.new(2025, 1, 15, 12, 0, 0, 0)) } + + it "shows the start year" do + expect(subject).to have_css(".meeting__calendar-year", text: "2024") + end + + it "shows the end year" do + expect(subject).to have_css(".meeting__calendar-year", text: "2025") + end + + it "shows year separator" do + expect(subject).to have_css(".meeting__calendar-separator") + end + end + + describe "#end_year" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/dates_and_map", meeting) } + + it "returns nil when end_time is blank" do + expect(my_cell.end_year).to be_nil + end + + it "returns formatted year when end_time is present" do + meeting.update!(end_time: Time.new(2021, 5, 20, 12, 0, 0, 0)) + expect(my_cell.end_year).to eq("2021") + end + end + + describe "#same_month?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/dates_and_map", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_month?)).to be true + end + + it "returns true when same month" do + meeting.update!(end_time: Time.new(2020, 10, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_month?)).to be true + end + + it "returns false when different months" do + meeting.update!(end_time: Time.new(2020, 11, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_month?)).to be false + end + + it "returns false when same month but different years" do + meeting.update!(end_time: Time.new(2021, 10, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_month?)).to be false + end + end + + describe "#same_day?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/dates_and_map", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_day?)).to be true + end + + it "returns true when same day" do + meeting.update!(end_time: Time.new(2020, 10, 15, 18, 0, 0, 0)) + expect(my_cell.send(:same_day?)).to be true + end + + it "returns false when different days" do + meeting.update!(end_time: Time.new(2020, 10, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_day?)).to be false + end + + it "returns false when same day but different years" do + meeting.update!(end_time: Time.new(2021, 10, 15, 12, 0, 0, 0)) + expect(my_cell.send(:same_day?)).to be false + end + end + + describe "#same_year?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/dates_and_map", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_year?)).to be true + end + + it "returns true when same year" do + meeting.update!(end_time: Time.new(2020, 12, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_year?)).to be true + end + + it "returns false when different years" do + meeting.update!(end_time: Time.new(2021, 1, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_year?)).to be false + end + end + end +end diff --git a/decidim-meetings/spec/cells/decidim/meetings/meeting_l_cell_spec.rb b/decidim-meetings/spec/cells/decidim/meetings/meeting_l_cell_spec.rb index d6f16ebcc1009..9a7fb5eff059f 100644 --- a/decidim-meetings/spec/cells/decidim/meetings/meeting_l_cell_spec.rb +++ b/decidim-meetings/spec/cells/decidim/meetings/meeting_l_cell_spec.rb @@ -28,6 +28,86 @@ module Decidim::Meetings it "shows the start time's year" do expect(subject).to have_css(".card__calendar-year", text: "2020") end + + it "does not show separator" do + expect(subject).to have_no_css(".card__calendar-separator") + end + end + + context "when meeting spans multiple days in the same month" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: Time.new(2020, 10, 17, 12, 0, 0, 0)) } + + it "shows the start day" do + expect(subject).to have_css(".card__calendar-day", text: "15") + end + + it "shows the end day" do + expect(subject).to have_css(".card__calendar-day", text: "17") + end + + it "shows the separator" do + expect(subject).to have_css(".card__calendar-separator") + end + + it "does not show month separator" do + expect(subject).to have_css(".card__calendar-month", text: "October") + end + end + + context "when meeting spans multiple months" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: Time.new(2020, 11, 17, 12, 0, 0, 0)) } + + it "shows the start month" do + expect(subject).to have_css(".card__calendar-month", text: "Oct") + end + + it "shows the end month" do + expect(subject).to have_css(".card__calendar-month", text: "Nov") + end + + it "shows the start day" do + expect(subject).to have_css(".card__calendar-day", text: "15") + end + + it "shows the end day" do + expect(subject).to have_css(".card__calendar-day", text: "17") + end + + it "shows month separator" do + expect(subject).to have_css(".card__calendar-separator") + end + end + + context "when meeting has no end time" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + + it "shows the start time's month" do + expect(subject).to have_css(".card__calendar-month", text: "October") + end + + it "shows the start time's day" do + expect(subject).to have_css(".card__calendar-day", text: "15") + end + + it "does not show separator" do + expect(subject).to have_no_css(".meeting__calendar-separator") + end + end + + context "when meeting spans multiple years" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 12, 15, 10, 0, 0, 0), end_time: Time.new(2021, 1, 17, 12, 0, 0, 0)) } + + it "shows the start year" do + expect(subject).to have_css(".card__calendar-year", text: "2020") + end + + it "shows the end year" do + expect(subject).to have_css(".card__calendar-year", text: "2021") + end + + it "shows the separator" do + expect(subject).to have_css(".card__calendar-separator") + end end context "when title contains special html entities" do @@ -43,5 +123,78 @@ module Decidim::Meetings expect(subject.to_s).to include("<strong>#{title}</strong> &'<") end end + + context "when show_space is false" do + let(:my_cell) { cell("decidim/meetings/meeting_l", meeting, context: { show_space: false }) } + + it "does not show the participatory space" do + expect(subject).to have_no_content(decidim_escape_translated(meeting.component.participatory_space.title)) + end + end + + context "when show_space is true" do + let(:my_cell) { cell("decidim/meetings/meeting_l", meeting, context: { show_space: true }) } + + it "shows the participatory space" do + expect(subject).to have_content(decidim_escape_translated(meeting.component.participatory_space.title)) + end + end + + describe "#same_month?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/meeting_l", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_month?)).to be true + end + + it "returns true when same month" do + meeting.update!(end_time: Time.new(2020, 10, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_month?)).to be true + end + + it "returns false when different months" do + meeting.update!(end_time: Time.new(2020, 11, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_month?)).to be false + end + end + + describe "#same_day?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/meeting_l", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_day?)).to be true + end + + it "returns true when same day" do + meeting.update!(end_time: Time.new(2020, 10, 15, 18, 0, 0, 0)) + expect(my_cell.send(:same_day?)).to be true + end + + it "returns false when different days" do + meeting.update!(end_time: Time.new(2020, 10, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_day?)).to be false + end + end + + describe "#same_year?" do + let!(:meeting) { create(:meeting, :published, start_time: Time.new(2020, 10, 15, 10, 0, 0, 0), end_time: nil) } + let(:my_cell) { cell("decidim/meetings/meeting_l", meeting) } + + it "returns true when end_time is blank" do + expect(my_cell.send(:same_year?)).to be true + end + + it "returns true when same year" do + meeting.update!(end_time: Time.new(2020, 12, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_year?)).to be true + end + + it "returns false when different years" do + meeting.update!(end_time: Time.new(2021, 1, 20, 12, 0, 0, 0)) + expect(my_cell.send(:same_year?)).to be false + end + end end end diff --git a/decidim-meetings/spec/cells/decidim/meetings/meeting_month_cell_spec.rb b/decidim-meetings/spec/cells/decidim/meetings/meeting_month_cell_spec.rb deleted file mode 100644 index b681b8a625d08..0000000000000 --- a/decidim-meetings/spec/cells/decidim/meetings/meeting_month_cell_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Meetings - describe MeetingMonthCell, type: :cell do - subject { my_cell.call } - - let!(:collection) { create_list(:meeting, 5, :published, start_time: Time.zone.local(2021, 5, 15)) } - let(:my_cell) { cell("decidim/meetings/meeting_month", collection, start_date:) } - - context "when the date is the same month" do - let(:start_date) { Time.zone.local(2021, 5, 1) } - - it "renders the date of the meetings" do - expect(subject).to have_css(".is-past-event") - end - - it "renders the month" do - expect(subject).to have_css("time", count: 31) - end - end - - context "when the date is a month without meetings" do - let(:start_date) { Time.zone.local(2021, 4, 1) } - - it "does not render any meeting" do - expect(subject).to have_no_css(".is-past-event") - end - - it "does not render the month" do - expect(subject).to have_css("time", count: 0) - end - end - end - end -end diff --git a/decidim-meetings/spec/controllers/decidim/meetings/directory/meetings_controller_spec.rb b/decidim-meetings/spec/controllers/decidim/meetings/directory/meetings_controller_spec.rb index f850a72bf20ba..f5df559d61f1f 100644 --- a/decidim-meetings/spec/controllers/decidim/meetings/directory/meetings_controller_spec.rb +++ b/decidim-meetings/spec/controllers/decidim/meetings/directory/meetings_controller_spec.rb @@ -52,4 +52,21 @@ end end end + + describe "GET index" do + render_views + + let(:params) { { filter: {} } } + + before do + get :index, params: + end + + it { expect(response).to have_http_status(:success) } + + it "shows the participatory space for each meeting" do + expect(response.body).to include(ERB::Util.html_escape(decidim_escape_translated(participatory_process1.title))) + expect(response.body).to include(ERB::Util.html_escape(decidim_escape_translated(participatory_process2.title))) + end + end end diff --git a/decidim-meetings/spec/models/meeting_spec.rb b/decidim-meetings/spec/models/meeting_spec.rb index c1ded521a2f03..891a144995733 100644 --- a/decidim-meetings/spec/models/meeting_spec.rb +++ b/decidim-meetings/spec/models/meeting_spec.rb @@ -454,7 +454,7 @@ module Decidim::Meetings let!(:proposals) do proposals = build_list(:proposal, 5, component: proposal_component) proposals.each do |proposal| - proposal.coauthorships.clear + proposal.coauthorships.target.clear proposal.coauthorships.build(author: meeting) proposal.save! end @@ -478,5 +478,35 @@ module Decidim::Meetings end end end + + describe "search index updates with linked meetings" do + let(:organization) { create(:organization, available_locales: [:en]) } + let(:space_a) { create(:participatory_process, organization:) } + let(:space_b) { create(:participatory_process, organization:) } + let(:component_a) { create(:meeting_component, participatory_space: space_a) } + let(:component_b) { create(:meeting_component, participatory_space: space_b) } + let!(:meeting_a) { create(:meeting, :published, component: component_a, title: { en: "Meeting A" }) } + let!(:meeting_b) { create(:meeting, :published, component: component_b, title: { en: "Meeting B" }) } + + before do + create(:meeting_link, meeting: meeting_a, component: component_b) + create(:meeting_link, meeting: meeting_b, component: component_a) + end + + it "does not enqueue descendants indexing indefinitely" do + clear_enqueued_jobs + clear_performed_jobs + + perform_enqueued_jobs(only: [Decidim::FindAndUpdateDescendantsJob, Decidim::UpdateSearchIndexesJob]) do + meeting_a.update!(title: { en: "Updated meeting A" }) + end + + find_jobs = performed_jobs.count { |job| job[:job] == Decidim::FindAndUpdateDescendantsJob } + update_jobs = performed_jobs.count { |job| job[:job] == Decidim::UpdateSearchIndexesJob } + + expect(find_jobs).to be <= Decidim::FindAndUpdateDescendantsJob::MAX_DEPTH + 1 + expect(update_jobs).to be <= Decidim::FindAndUpdateDescendantsJob::MAX_DEPTH + end + end end end diff --git a/decidim-meetings/spec/system/admin/admin_manages_component_publication_spec.rb b/decidim-meetings/spec/system/admin/admin_manages_component_publication_spec.rb new file mode 100644 index 0000000000000..1ba5cfec32d69 --- /dev/null +++ b/decidim-meetings/spec/system/admin/admin_manages_component_publication_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages component publication" do + include_context "when managing a component as an admin" do + let!(:resource) { create(:meeting, :published, component:) } + + context "when cycling through publication states" do + let!(:component) { create(:meeting_component, participatory_space:) } + + include_examples "cycling through publication states" + end + + context "when component is unpublished, and admin publishes" do + let!(:component) { create(:meeting_component, :unpublished, participatory_space:) } + + include_examples "add component resources to search index" + end + + context "when component is published, and admin unpublishes" do + let!(:component) { create(:meeting_component, :published, participatory_space:) } + + include_examples "removes component resources from search index" + end + end +end diff --git a/decidim-meetings/spec/system/admin/admin_manages_meetings_links_spec.rb b/decidim-meetings/spec/system/admin/admin_manages_meetings_links_spec.rb index 15311eed63e9b..c23444f7d3133 100644 --- a/decidim-meetings/spec/system/admin/admin_manages_meetings_links_spec.rb +++ b/decidim-meetings/spec/system/admin/admin_manages_meetings_links_spec.rb @@ -23,6 +23,20 @@ expect(page).to have_css("tbody tr:first-child", text: Decidim::Meetings::MeetingPresenter.new(other_meeting).title) expect(page).to have_css("tbody tr:last-child", text: Decidim::Meetings::MeetingPresenter.new(meeting).title) end + + it "redirects to the proper edit meeting page, outside the linked meeting" do + expect(resource_locator(meeting).admin_index).to include(current_path) + + within "tr", text: Decidim::Meetings::MeetingPresenter.new(other_meeting).title do + expect(page).to have_content("This meeting must be edited from") + click_on translated(other_participatory_space.title) + end + + expect(page).to have_current_path(resource_locator(other_meeting).edit) + click_on "Update" + + expect(page).to have_current_path(resource_locator(other_meeting).admin_index) + end end describe "linking a meeting" do @@ -44,6 +58,7 @@ expect do click_on "Update" + sleep 1 end.to change { meeting.meeting_links.count }.by(1) end end diff --git a/decidim-meetings/spec/system/admin/admin_manages_meetings_polls_spec.rb b/decidim-meetings/spec/system/admin/admin_manages_meetings_polls_spec.rb index d9dbd4d094b8a..6eb41594033a4 100644 --- a/decidim-meetings/spec/system/admin/admin_manages_meetings_polls_spec.rb +++ b/decidim-meetings/spec/system/admin/admin_manages_meetings_polls_spec.rb @@ -26,7 +26,7 @@ click_on "Manage poll" end - expect(page).to have_content("Edit poll questionnaire for #{Decidim::Meetings::MeetingPresenter.new(meeting).title}") + expect(page).to have_content("Edit poll") end end diff --git a/decidim-meetings/spec/system/admin/admin_manages_meetings_spec.rb b/decidim-meetings/spec/system/admin/admin_manages_meetings_spec.rb index 306cdd8a53eca..9590085050add 100644 --- a/decidim-meetings/spec/system/admin/admin_manages_meetings_spec.rb +++ b/decidim-meetings/spec/system/admin/admin_manages_meetings_spec.rb @@ -410,7 +410,6 @@ expect(page).to have_callout("Meeting successfully created. Notice this is unpublished yet, you need to manually publish it.") new_meeting = Decidim::Meetings::Meeting.last - puts "Meeting location: #{new_meeting.location}" expect(new_meeting.location.values).to all(be_blank) expect(new_meeting.address).to be_empty end diff --git a/decidim-meetings/spec/system/admin/admin_publishes_component_spec.rb b/decidim-meetings/spec/system/admin/admin_publishes_component_spec.rb deleted file mode 100644 index 4495b5163d72f..0000000000000 --- a/decidim-meetings/spec/system/admin/admin_publishes_component_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Admin publishes component" do - let(:manifest_name) { "meetings" } - let!(:resource) { create(:meeting, :published, component:) } - - include_context "when publishing and unpublishing the component" - include_context "when cycling through publication states" -end diff --git a/decidim-meetings/spec/system/admin/filter_meetings_spec.rb b/decidim-meetings/spec/system/admin/filter_meetings_spec.rb index 70abcb86e05a1..1b6e7a7cb7d23 100644 --- a/decidim-meetings/spec/system/admin/filter_meetings_spec.rb +++ b/decidim-meetings/spec/system/admin/filter_meetings_spec.rb @@ -38,10 +38,8 @@ def meeting_without_type(type) before { visit_component_admin } TYPES.each do |state| - i18n_state = I18n.t(state, scope: "decidim.admin.filters.meetings.with_any_type.values") - - context "when filtering meetings by type: #{i18n_state}" do - it_behaves_like "a filtered collection", options: "Type", filter: i18n_state do + context "when filtering meetings by type: #{I18n.t(state, scope: "decidim.admin.filters.meetings.with_any_type.values")}" do + it_behaves_like "a filtered collection", options: "Type", filter: I18n.t(state, scope: "decidim.admin.filters.meetings.with_any_type.values") do let(:in_filter) { translated(meeting_with_type(state).title) } let(:not_in_filter) { translated(meeting_without_type(state).title) } end diff --git a/decidim-meetings/spec/system/directory_meetings_spec.rb b/decidim-meetings/spec/system/directory_meetings_spec.rb new file mode 100644 index 0000000000000..4ceafc268e273 --- /dev/null +++ b/decidim-meetings/spec/system/directory_meetings_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Global meetings directory", :slow do + let(:organization) { create(:organization) } + let!(:participatory_process1) { create(:participatory_process, organization:) } + let!(:meeting_component1) { create(:meeting_component, participatory_space: participatory_process1) } + let!(:participatory_process2) { create(:participatory_process, organization:) } + let!(:meeting_component2) { create(:meeting_component, participatory_space: participatory_process2) } + + let!(:meeting1) do + create(:meeting, :published, :upcoming, title: { en: "First meeting" }, component: meeting_component1) + end + let!(:meeting2) do + create(:meeting, :published, :upcoming, title: { en: "Second meeting" }, component: meeting_component1) + end + let!(:meeting3) do + create(:meeting, :published, :upcoming, title: { en: "Third meeting" }, component: meeting_component2) + end + + before do + switch_to_host(organization.host) + visit Decidim::Meetings::DirectoryEngine.routes.url_helpers.root_path + end + + it "shows all meetings from all participatory spaces" do + within ".layout-2col__main" do + expect(page).to have_content("First meeting") + expect(page).to have_content("Second meeting") + expect(page).to have_content("Third meeting") + end + end + + it "shows the participatory space name for each meeting in the main list" do + within ".layout-2col__main" do + expect(page).to have_content(decidim_escape_translated(participatory_process1.title)) + expect(page).to have_content(decidim_escape_translated(participatory_process2.title)) + end + end +end diff --git a/decidim-meetings/spec/system/meeting_spec.rb b/decidim-meetings/spec/system/meeting_spec.rb index f798a7f8660e9..a51dae4ed4a25 100644 --- a/decidim-meetings/spec/system/meeting_spec.rb +++ b/decidim-meetings/spec/system/meeting_spec.rb @@ -197,22 +197,6 @@ def visit_meeting travel 1.minute expect(page).to have_content("You were inactive for too long") end - - context "when comments are enabled" do - let(:comment) { create(:comment, commentable: meeting) } - - before do - component.settings[:comments_enabled] = true - end - - it "fetching comments does not prevent timeout" do - visit_meeting - comment - expect(page).to have_content(translated(comment.body), wait: 30) - expect(page).to have_content("If you continue being inactive", wait: 30) - expect(page).to have_content("You were inactive for too long", wait: 30) - end - end end end end diff --git a/decidim-pages/app/controllers/decidim/pages/admin/pages_controller.rb b/decidim-pages/app/controllers/decidim/pages/admin/pages_controller.rb index 0e7f40cfb3cf8..24bb6dc4827df 100644 --- a/decidim-pages/app/controllers/decidim/pages/admin/pages_controller.rb +++ b/decidim-pages/app/controllers/decidim/pages/admin/pages_controller.rb @@ -26,7 +26,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("pages.update.invalid", scope: "decidim.pages.admin") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-pages/spec/system/admin_manages_component_publication_spec.rb b/decidim-pages/spec/system/admin_manages_component_publication_spec.rb new file mode 100644 index 0000000000000..eace8ac13d7a0 --- /dev/null +++ b/decidim-pages/spec/system/admin_manages_component_publication_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages component publication" do + let!(:resource) { create(:page, component:) } + + # Note: other components also handle search index updates (additions/removals) when publishing or + # unpublishing. This component is excluded from general search, so those operations are not implemented here. + include_context "when managing a component as an admin" do + context "when cycling through publication states" do + let!(:component) { create(:page_component, participatory_space:) } + + include_examples "cycling through publication states" + end + end +end diff --git a/decidim-pages/spec/system/admin_publishes_component_spec.rb b/decidim-pages/spec/system/admin_publishes_component_spec.rb deleted file mode 100644 index 9b2fc5870f6b5..0000000000000 --- a/decidim-pages/spec/system/admin_publishes_component_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Admin publishes component" do - let(:manifest_name) { "pages" } - let!(:resource) { create(:page, component:) } - - include_context "when cycling through publication states" -end diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/concerns/participatory_process_admin.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/concerns/participatory_process_admin.rb index 320dda5af3618..55920b67d2c26 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/concerns/participatory_process_admin.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/concerns/participatory_process_admin.rb @@ -19,6 +19,7 @@ module ParticipatoryProcessAdmin included do include Decidim::Admin::ParticipatorySpaceAdminContext + helper_method :current_participatory_process add_breadcrumb_item_from_menu :admin_participatory_process_menu diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_duplicates_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_duplicates_controller.rb index c080625cebc76..6e0f6a25d336f 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_duplicates_controller.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_duplicates_controller.rb @@ -25,7 +25,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("participatory_processes_duplicates.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_groups_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_groups_controller.rb index 830d081110c25..3ba0e569aaace 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_groups_controller.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_groups_controller.rb @@ -36,7 +36,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("participatory_processes_group.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -61,7 +61,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("participatory_process_groups.update.error", scope: "decidim.admin") - render :edit, layout: "decidim/admin/participatory_process_group", status: :unprocessable_entity + render :edit, layout: "decidim/admin/participatory_process_group", status: :unprocessable_content end end end @@ -78,7 +78,7 @@ def destroy on(:invalid) do flash.now[:alert] = I18n.t("participatory_process_groups.destroy.error", scope: "decidim.admin") - render :index, status: :unprocessable_entity + render :index, status: :unprocessable_content end end end diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_imports_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_imports_controller.rb index 0957110f410ca..68c82904e0b6c 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_imports_controller.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_imports_controller.rb @@ -26,7 +26,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("participatory_process_imports.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_steps_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_steps_controller.rb index 5c69d98f08d95..868568c4794ec 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_steps_controller.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_steps_controller.rb @@ -32,7 +32,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("participatory_process_steps.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -54,15 +54,11 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("participatory_process_steps.update.error", scope: "decidim.admin") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end - def show - enforce_permission_to :read, :process_step, process_step: @participatory_process_step - end - def destroy enforce_permission_to :destroy, :process_step, process_step: @participatory_process_step diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_processes_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_processes_controller.rb index 49955f275e7d0..a8dc03b01a3bb 100644 --- a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_processes_controller.rb +++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_processes_controller.rb @@ -42,7 +42,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("participatory_processes.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -68,7 +68,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("participatory_processes.update.error", scope: "decidim.admin") - render :edit, layout: "decidim/admin/participatory_process", status: :unprocessable_entity + render :edit, layout: "decidim/admin/participatory_process", status: :unprocessable_content end end end diff --git a/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/admin_users.rb b/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/admin_users.rb index d000946635e53..cefd91db5811a 100644 --- a/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/admin_users.rb +++ b/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/admin_users.rb @@ -43,7 +43,7 @@ def query def processes_user_admins Decidim::User.where( id: Decidim::ParticipatoryProcessUserRole.where(participatory_process: processes, role: :admin) - .select(:decidim_user_id) + .select(:decidim_user_id) ) end diff --git a/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/moderators.rb b/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/moderators.rb index dabc4b3dcba0a..5f573fb55d600 100644 --- a/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/moderators.rb +++ b/decidim-participatory_processes/app/queries/decidim/participatory_processes/admin/moderators.rb @@ -44,7 +44,7 @@ def query def processes_user_admins Decidim::User.where( id: Decidim::ParticipatoryProcessUserRole.where(participatory_process: processes) - .where.not(role: :collaborator) + .where.not(role: :collaborator) .select(:decidim_user_id) ) end diff --git a/decidim-participatory_processes/app/serializers/decidim/participatory_processes/participatory_process_importer.rb b/decidim-participatory_processes/app/serializers/decidim/participatory_processes/participatory_process_importer.rb index 126133e444e13..1af3fc62f7938 100644 --- a/decidim-participatory_processes/app/serializers/decidim/participatory_processes/participatory_process_importer.rb +++ b/decidim-participatory_processes/app/serializers/decidim/participatory_processes/participatory_process_importer.rb @@ -106,27 +106,24 @@ def import_folders_and_attachments(attachments) next end - begin - file_tmp = URI.parse(url).open - rescue OpenURI::HTTPError, Errno::ENOENT, Errno::ECONNREFUSED, SocketError, Net::OpenTimeout, Net::ReadTimeout => e - @warnings << I18n.t( - "decidim.participatory_processes.admin.imports.attachment_error", - title: attachment_title(file), - error: format_error(e) - ) - next - end - Decidim.traceability.perform_action!("create", Attachment, @user) do attachment = Attachment.new( title: file["title"], description: file["description"], - content_type: file_tmp.content_type, attached_to: @imported_process, - weight: file["weight"], - file: file_tmp, # Define attached_to before this - file_size: file_tmp.size + weight: file["weight"] ) + begin + attachment.attached_uploader(:file).remote_url = url + attachment.set_content_type_and_size + rescue OpenURI::HTTPError, Errno::ENOENT, Errno::ECONNREFUSED, SocketError, Net::OpenTimeout, Net::ReadTimeout => e + @warnings << I18n.t( + "decidim.participatory_processes.admin.imports.attachment_error", + title: attachment_title(file), + error: format_error(e) + ) + next + end attachment.create_attachment_collection(file["attachment_collection"]) attachment.save! attachment diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_duplicates/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_duplicates/new.html.erb index 0b86906e35a9f..453467552341a 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_duplicates/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_duplicates/new.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("participatory_process_duplicates.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("participatory_process_duplicates.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/edit.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/edit.html.erb index bf06b8f11e0a6..5d1efaf521881 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/edit.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/edit.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title t("participatory_process_groups.edit.title", scope: "decidim.admin") %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t "participatory_process_groups.edit.title", scope: "decidim.admin" %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/index.html.erb index 609f5d6ad5147..97f69234498f6 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/index.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/index.html.erb @@ -1,4 +1,5 @@ -<% add_decidim_page_title(t("decidim.admin.titles.participatory_process_groups")) %> +<% add_decidim_page_title(t(".title")) %> + <% content_for :breadcrumb_context_menu do %>
<% if allowed_to? :create, :process_group %> diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/new.html.erb index dc62ebe632e85..866f6ff9be183 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_groups/new.html.erb @@ -1,4 +1,5 @@ -<% add_decidim_page_title(t("participatory_process_groups.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> + <% content_for :breadcrumb_context_menu do %>
<% if allowed_to? :create, :process_group %> @@ -13,7 +14,7 @@ <% end %>

- <%= t "participatory_process_groups.new.title", scope: "decidim.admin" %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_imports/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_imports/new.html.erb index 8b9f2272da630..fe6ec2ccb5dcf 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_imports/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_imports/new.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("participatory_process_imports.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("participatory_process_imports.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/edit.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/edit.html.erb index 53bf5c077470c..347615aa4e796 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/edit.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/edit.html.erb @@ -1,15 +1,15 @@ -<% add_decidim_page_title(t("participatory_process_steps.edit.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("participatory_process_steps.edit.title", scope: "decidim.admin") %> + <%= t(".title") %>

<%= decidim_form_for(@form, url: participatory_process_step_path(@participatory_process_step.participatory_process, @participatory_process_step), html: { class: "form form-defaults edit_participatory_process_step" }) do |f| %> - <%= render partial: "form", object: f, locals: { title: t("participatory_process_steps.edit.title", scope: "decidim.admin") } %> + <%= render partial: "form", object: f, locals: { title: t(".title") } %>
<%= f.submit t("participatory_process_steps.edit.update", scope: "decidim.admin"), class: "button button__sm button__secondary" %> diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/index.html.erb index 5f71fdcf7ac99..64d9e6462e7b9 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/index.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/index.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("participatory_process_steps.index.steps_title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("participatory_process_steps.index.steps_title", scope: "decidim.admin") %> + <%= t(".title") %> <% if allowed_to? :create, :process_step %> <%= link_to t("actions.new_process_step", scope: "decidim.admin"), new_participatory_process_step_path(current_participatory_process), class: "button button__sm button__secondary ml-auto" %> <% end %> @@ -24,7 +25,7 @@ ">
- <%= icon "drag-move-2-line" %> + <%= icon("draggable", class: "dragger hover:cursor-grab") %> <% if step.active? %> <% end %> diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/new.html.erb index 4cab80e9389d8..58fd0ff6013e1 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/new.html.erb @@ -1,14 +1,15 @@ -<% add_decidim_page_title(t("participatory_process_steps.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("participatory_process_steps.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

<%= decidim_form_for(@form, html: { class: "form form-defaults new_participatory_process_step" }) do |f| %> - <%= render partial: "form", object: f, locals: { title: t("participatory_process_steps.new.title", scope: "decidim.admin") } %> + <%= render partial: "form", object: f, locals: { title: t(".title") } %>
diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/show.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/show.html.erb deleted file mode 100644 index f228ec061be18..0000000000000 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_steps/show.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -

<%= translated_attribute(@participatory_process_step.title) %>

- -
-
- <%= link_to t("decidim.admin.actions.edit"), edit_participatory_process_step_path(participatory_process, @participatory_process_step) if allowed_to? :update, :process_step, process_step: @participatory_process_step %> - <%= link_to t("decidim.admin.actions.destroy"), participatory_process_step_path(participatory_process, @participatory_process_step), method: :delete, class: "alert button", data: { confirm: t("decidim.admin.actions.confirm_destroy") } if allowed_to? :destroy, :process_step, process_step: @participatory_process_step %> -
- -
- <%= display_for @participatory_process_step, - :title, - :description %> -
<%= display_label(@participatory_process_step, :start_date) %>
-
<%= l @participatory_process_step.start_date, format: :short if @participatory_process_step.start_date.present? %>
-
<%= display_label(@participatory_process_step, :end_date) %>
-
<%= l @participatory_process_step.end_date, format: :short if @participatory_process_step.end_date.present? %>
-
diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/edit.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/edit.html.erb index 46b89d6a4c051..35bcef60f99b0 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/edit.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/edit.html.erb @@ -1,15 +1,15 @@ -<% add_decidim_page_title(t("participatory_process_user_roles.edit.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("participatory_process_user_roles.edit.title", scope: "decidim.admin") %> + <%= t(".title") %>

<%= decidim_form_for(@form, url: participatory_process_user_role_path(@user_role.participatory_process, @user_role), html: { class: "form-defaults form edit_participatory_process_user_roles" }) do |f| %> - <%= render partial: "form", object: f, locals: { title: t("participatory_process_user_roles.edit.title", scope: "decidim.admin") } %> + <%= render partial: "form", object: f, locals: { title: t(".title") } %>
<%= f.submit t("participatory_process_user_roles.edit.update", scope: "decidim.admin"), class: "button button__sm button__secondary" %> diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/index.html.erb index 93fa5b340d614..0cdea26aa096d 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/index.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/index.html.erb @@ -1,9 +1,9 @@ -<% add_decidim_page_title(t("participatory_process_user_roles.index.process_admins_title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("participatory_process_user_roles.index.process_admins_title", scope: "decidim.admin") %> + <%= t(".title") %> <% if allowed_to? :create, :process_user_role %> <%= link_to t("actions.new_process_user_role", scope: "decidim.admin"), new_participatory_process_user_role_path(current_participatory_process), class: "button button__sm button__secondary new ml-auto" %> <% end %> diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/new.html.erb index 8df60774ca754..c01785f8aa94c 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_process_user_roles/new.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("participatory_process_user_roles.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("participatory_process_user_roles.new.title", scope: "decidim.admin") %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/edit.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/edit.html.erb index 6c588bb90d171..05eb5071e3d17 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/edit.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/edit.html.erb @@ -1,8 +1,9 @@ -<% add_decidim_page_title(t("info", scope: "decidim.admin.menu.participatory_processes_submenu")) %> +<% add_decidim_page_title(t(".title")) %> <% add_decidim_page_title(translated_attribute(current_participatory_space.title)) %> +

- <%= t("info", scope: "decidim.admin.menu.participatory_processes_submenu") %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb index 4fb5ac719ac88..a61185ac52125 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb @@ -1,4 +1,5 @@ -<% add_decidim_page_title(t("participatory_processes", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %> + <%= admin_tabs(:admin_participatory_processes_menu).render %>
diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/manage_trash.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/manage_trash.html.erb index 52f309289e32c..1c8c3b2d3e05f 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/manage_trash.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/manage_trash.html.erb @@ -1,8 +1,8 @@ -<% add_decidim_page_title(t("participatory_processes_deleted", scope: "decidim.admin.titles")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t "participatory_processes.manage_trash.title", scope: "decidim.admin" %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/new.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/new.html.erb index 563e5df990e3a..e6843165ab7dc 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/new.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/new.html.erb @@ -1,7 +1,8 @@ -<% add_decidim_page_title(t("participatory_processes.new.title", scope: "decidim.admin")) %> +<% add_decidim_page_title(t(".title")) %> +

- <%= t("title", scope: "decidim.admin.participatory_processes.new") %> + <%= t(".title") %>

diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/members/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/members/index.html.erb index 3f3d8461c4f56..be6be3ee4ece3 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/members/index.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/members/index.html.erb @@ -1,4 +1,4 @@ -<% add_decidim_page_title(t(".title")) %> +<% add_decidim_page_title(t("members", scope: "decidim.participatory_space_members.index")) %> <% add_decidim_meta_tags( title: translated_attribute(current_participatory_space.title), resource: current_participatory_space) %> @@ -11,12 +11,14 @@ edit_link( ) %> -
-

- <%= t("members", scope: "decidim.assemblies.assembly_members.index") %> - <%= collection.size %> -

-
+<% content_for :aside do %> +

+ <%= t("members", scope: "decidim.participatory_space_members.index") %> +

+<% end %> + +<%= render layout: "layouts/decidim/shared/layout_two_col" do %> +
<%= render(collection) %> -
-
+

+<% end %> diff --git a/decidim-participatory_processes/config/locales/en.yml b/decidim-participatory_processes/config/locales/en.yml index 7d5060fdb9e86..8612c74806f80 100644 --- a/decidim-participatory_processes/config/locales/en.yml +++ b/decidim-participatory_processes/config/locales/en.yml @@ -109,7 +109,6 @@ en: menu: participatory_process_groups: Process groups participatory_process_groups_submenu: - info: About this process group landing_page: Landing page layout participatory_processes: Processes participatory_processes_submenu: @@ -117,7 +116,6 @@ en: attachment_files: Files attachments: Attachments components: Components - info: About this process landing_page: Landing page layout members: Members moderations: Moderations @@ -165,17 +163,14 @@ en: new: duplicate: Duplicate select: Select which data you would like to duplicate - title: Duplicate participatory process participatory_process_groups: destroy: error: There was a problem while destroying the participatory process group. success: Participatory process group successfully deleted. edit: - title: Edit process group update: Update new: create: Create - title: New process group update: error: There was a problem updating this participatory process group. success: Participatory process group successfully updated. @@ -186,7 +181,6 @@ en: new: import: Import select: Select which data you would like to import - title: Import participatory process participatory_process_publications: create: error: There was a problem publishing this participatory process. @@ -209,13 +203,9 @@ en: last_step: Cannot delete the last phase of a process. success: Participatory process phase successfully deleted. edit: - title: Edit participatory process phase update: Update - index: - steps_title: Phases new: create: Create - title: New participatory process phase ordering: error: There was a problem in reordering these phases of the participatory process. update: @@ -228,13 +218,9 @@ en: destroy: success: Admin successfully removed from this participatory process. edit: - title: Update participatory process admin update: Update - index: - process_admins_title: Participatory process admins new: create: Create - title: New participatory process admin update: error: There was a problem updating an admin for this participatory process. success: Admin successfully updated for this participatory process. @@ -249,11 +235,8 @@ en: public: Public published: Published unpublished: Unpublished - manage_trash: - title: Deleted participatory processes new: create: Create - title: New participatory process update: error: There was a problem updating this participatory process. success: Participatory process successfully updated. @@ -269,10 +252,7 @@ en: space_filter_for: participatory_processes: All participatory processes titles: - participatory_process_groups: Participatory process groups participatory_process_types: Participatory process types - participatory_processes: Participatory processes - participatory_processes_deleted: Deleted participatory processes tooltips: deleted_processes_info: A process can only be deleted if status is "Unpublished". users: @@ -501,16 +481,42 @@ en: participatory_process_duplicates: form: slug_help_html: 'URL slugs are used to generate the URLs that point to this process. Only accepts letters, numbers and dashes, and must start with a letter. Example: %{url}' + new: + title: Duplicate participatory process participatory_process_groups: + edit: + title: Edit process group form: metadata: Metadata title: About this process visibility: Visibility + index: + title: Participatory process groups + new: + title: New process group participatory_process_imports: form: document_legend: Add a document slug_help_html: 'URL slugs are used to generate the URLs that point to this process. Only accepts letters, numbers and dashes, and must start with a letter. Example: %{url}' + new: + title: Import participatory process + participatory_process_steps: + edit: + title: Edit participatory process phase + index: + title: Phases + new: + title: New participatory process phase + participatory_process_user_roles: + edit: + title: Update participatory process admin + index: + title: Participatory process admins + new: + title: New participatory process admin participatory_processes: + edit: + title: About this process form: define_taxonomy_filters: Please define some filters for this participatory space before using this setting. duration: Duration @@ -525,6 +531,12 @@ en: taxonomies: Taxonomies title: General Information visibility: Visibility + index: + title: Participatory processes + manage_trash: + title: Deleted participatory processes + new: + title: New participatory process content_blocks: democratic_quality_stats: automatic_metrics: @@ -567,9 +579,6 @@ en: title: Participatory processes last_activity: new_participatory_process: 'New participatory process:' - members: - index: - title: Members pages: home: highlighted_processes: diff --git a/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb b/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb index cf770a3ad2b2d..1d7d0e4bb59ef 100644 --- a/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb +++ b/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb @@ -31,7 +31,7 @@ class AdminEngine < ::Rails::Engine patch :restore end - resources :steps, controller: "participatory_process_steps" do + resources :steps, controller: "participatory_process_steps", except: [:show] do resource :activate, controller: "participatory_process_step_activations", only: [:create, :destroy] collection do post :ordering, to: "participatory_process_step_ordering#create" diff --git a/decidim-participatory_processes/lib/decidim/participatory_processes/engine.rb b/decidim-participatory_processes/lib/decidim/participatory_processes/engine.rb index def6358ac8d77..ae7a38f3d003d 100644 --- a/decidim-participatory_processes/lib/decidim/participatory_processes/engine.rb +++ b/decidim-participatory_processes/lib/decidim/participatory_processes/engine.rb @@ -43,18 +43,17 @@ class Engine < ::Rails::Engine end get "/participatory_process_groups/*rest", to: redirect { |params, request| - locale = params[:locale] || request.session[:user_locale] || I18n.locale + locale = Decidim::LocaleRouterDetector.new(request, params).locale "/#{locale}/processes_groups/#{params[:rest]}" } get "/processes", to: redirect { |params, request| - locale = params[:locale] || request.session[:user_locale] || I18n.locale + locale = Decidim::LocaleRouterDetector.new(request, params).locale "/#{locale}/processes" } get "/processes/*rest", to: redirect { |params, request| - locale = params[:locale] || request.session[:user_locale] || I18n.locale - + locale = Decidim::LocaleRouterDetector.new(request, params).locale "/#{locale}/processes/#{params[:rest]}" } end diff --git a/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb b/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb index 2fd81e413e2b5..4f3a3e240d476 100644 --- a/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb +++ b/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb @@ -109,7 +109,7 @@ def self.register_admin_participatory_process_components_menu! def self.register_admin_participatory_process_menu! Decidim.menu :admin_participatory_process_menu do |menu| menu.add_item :edit_participatory_process, - I18n.t("info", scope: "decidim.admin.menu.participatory_processes_submenu"), + I18n.t("title", scope: "decidim.participatory_processes.admin.participatory_processes.edit"), decidim_admin_participatory_processes.edit_participatory_process_path(current_participatory_space), active: is_active_link?(decidim_admin_participatory_processes.edit_participatory_process_path(current_participatory_space)), icon_name: "information-line", @@ -179,7 +179,7 @@ def self.register_admin_participatory_process_menu! def self.register_admin_participatory_process_group_menu! Decidim.menu :admin_participatory_process_group_menu do |menu| menu.add_item :edit_participatory_process_group, - I18n.t("info", scope: "decidim.admin.menu.participatory_process_groups_submenu"), + I18n.t("title", scope: "decidim.participatory_processes.admin.participatory_process_groups.edit"), decidim_admin_participatory_processes.edit_participatory_process_group_path(participatory_process_group), position: 1, icon_name: "information-line", diff --git a/decidim-participatory_processes/spec/requests/redirect_routes_spec.rb b/decidim-participatory_processes/spec/requests/redirect_routes_spec.rb new file mode 100644 index 0000000000000..e88d10174306b --- /dev/null +++ b/decidim-participatory_processes/spec/requests/redirect_routes_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Redirect routes" do + let(:organization) { create(:organization, available_locales: %w(en es ca), default_locale: "en") } + let(:headers) { { "HOST" => organization.host } } + + context "when there is a participatory process" do + it "redirects old url with missing locale" do + get("/processes", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/en/processes") + end + + it "redirects old url with locale" do + get("/processes?locale=es", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/es/processes") + end + + it "redirects to default locale when the locale is invalid" do + get("/processes?locale=esp", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/en/processes") + end + + it "redirects old url with locale and additional params" do + get("/processes/foo-bar?locale=es", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/es/processes/foo-bar") + end + + it "redirects user to the new url" do + user = create(:user, :confirmed, organization:, locale: "ca") + login_as user, scope: :user + + get("/", headers:) + get("/processes", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/ca/processes") + end + + it "redirects user to the new url when using custom locale" do + user = create(:user, :confirmed, organization:, locale: "ca") + login_as user, scope: :user + + get("/", headers:) + get("/processes?locale=es", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/es/processes") + end + end + + context "when there is a participatory process group" do + it "redirects old url with locale and additional params" do + get("/participatory_process_groups/foo-bar?locale=es", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/es/processes_groups/foo-bar") + end + + it "redirects user to the new url" do + user = create(:user, :confirmed, organization:, locale: "ca") + login_as user, scope: :user + + get("/", headers:) + get("/participatory_process_groups/foo-bar", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/ca/processes_groups/foo-bar") + end + + it "redirects user to the new url when using custom locale" do + user = create(:user, :confirmed, organization:, locale: "ca") + login_as user, scope: :user + + get("/", headers:) + get("/participatory_process_groups/foo-bar?locale=es", headers:) + expect(response).to have_http_status(:moved_permanently) + expect(response).to redirect_to("/es/processes_groups/foo-bar") + end + end +end diff --git a/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_importer_spec.rb b/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_importer_spec.rb index 4ab4d7159ba7b..6408dd7ddc46b 100644 --- a/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_importer_spec.rb +++ b/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_importer_spec.rb @@ -387,6 +387,114 @@ module Decidim::ParticipatoryProcesses expect(importer.warnings).to include(a_string_matching(/The attachment "Test File" could not be imported \(500 Internal Server Error\)\./i)) end end + + context "when remote file is accessible and downloadable (PDF)" do + let(:remote_file_url) { "http://example.com/document.pdf" } + + before do + stub_request(:head, remote_file_url) + .to_return(status: 200, headers: { "Content-Type" => "application/pdf" }) + stub_request(:get, remote_file_url) + .to_return(status: 200, body: File.read(Decidim::Dev.asset("Exampledocument.pdf"))) + end + + it "successfully imports the attachment" do + expect { importer.import_folders_and_attachments(attachments_data) } + .to change(Decidim::Attachment, :count).by(1) + end + + it "attaches the file to the process" do + importer.import_folders_and_attachments(attachments_data) + attachment = Decidim::Attachment.last + expect(attachment.file).to be_attached + expect(attachment.file.filename.to_s).to eq("document.pdf") + end + + it "sets the content type automatically" do + importer.import_folders_and_attachments(attachments_data) + attachment = Decidim::Attachment.last + expect(attachment.content_type).to eq("application/pdf") + end + + it "sets the file size automatically" do + importer.import_folders_and_attachments(attachments_data) + attachment = Decidim::Attachment.last + expect(attachment.file_size).to be_present + end + + it "has no warnings" do + importer.import_folders_and_attachments(attachments_data) + expect(importer.warnings).to be_empty + end + end + + context "when remote file is accessible and downloadable (image)" do + let(:remote_file_url) { "http://example.com/image.jpg" } + + before do + stub_request(:head, remote_file_url) + .to_return(status: 200, headers: { "Content-Type" => "image/jpeg" }) + stub_request(:get, remote_file_url) + .to_return(status: 200, body: File.read(Decidim::Dev.asset("city.jpeg"))) + end + + it "successfully imports the attachment" do + expect { importer.import_folders_and_attachments(attachments_data) } + .to change(Decidim::Attachment, :count).by(1) + end + + it "attaches the file to the process" do + importer.import_folders_and_attachments(attachments_data) + attachment = Decidim::Attachment.last + expect(attachment.file).to be_attached + end + + it "sets the content type automatically" do + importer.import_folders_and_attachments(attachments_data) + attachment = Decidim::Attachment.last + expect(attachment.content_type).to eq("image/jpeg") + end + + it "has no warnings" do + importer.import_folders_and_attachments(attachments_data) + expect(importer.warnings).to be_empty + end + end + + context "when remote file URL is blank" do + let(:attachments_data) do + { + "files" => [ + { + "title" => { "en" => "Test File" }, + "description" => { "en" => "Test Description" }, + "weight" => 1, + "remote_file_url" => "" + } + ], + "attachment_collections" => [] + } + end + + it "does not create any attachments" do + expect { importer.import_folders_and_attachments(attachments_data) } + .not_to change(Decidim::Attachment, :count) + end + end + + context "when files array is nil" do + let(:attachments_data) do + { + "files" => nil, + "attachment_collections" => [] + } + end + + it "does not create any attachments" do + expect { importer.import_folders_and_attachments(attachments_data) } + .not_to change(Decidim::Attachment, :count) + end + end end end end diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_cell.rb b/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_cell.rb deleted file mode 100644 index 7bbb2c0c09854..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_cell.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require "cell/partial" - -module Decidim - module Proposals - # This cell renders the collaborative_draft card for an instance of a CollaborativeDraft - # the default size is the Medium Card (:m) - class CollaborativeDraftCell < Decidim::ViewModel - include CollaborativeDraftCellsHelper - include Cell::ViewModel::Partial - include Messaging::ConversationHelper - - def show - cell card_size, model, @options - end - - private - - def card_size - "decidim/proposals/collaborative_draft_l" - end - - def resource_path - resource_locator(model).path - end - - def current_participatory_space - model.component.participatory_space - end - - def component_name - translated_attribute current_component.name - end - - def component_type_name - model.class.model_name.human - end - - def participatory_space_name - translated_attribute current_participatory_space.title - end - - def participatory_space_type_name - translated_attribute current_participatory_space.model_name.human - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_l_cell.rb b/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_l_cell.rb deleted file mode 100644 index afc3f408f5504..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_l_cell.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require "cell/partial" - -module Decidim - module Proposals - # This cell renders a proposal with its L-size card. - class CollaborativeDraftLCell < Decidim::CardLCell - private - - def metadata_cell - "decidim/proposals/collaborative_draft_metadata" - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal/show.erb b/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal/show.erb deleted file mode 100644 index 2088d3586cc17..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal/show.erb +++ /dev/null @@ -1,5 +0,0 @@ -
-

<%= t("final_proposal", scope: "decidim.proposals.collaborative_drafts.show") %>

-

<%= t("final_proposal_help_text", scope: "decidim.proposals.collaborative_drafts.show") %>

- <%= link_to t("published_proposal", scope: "decidim.proposals.collaborative_drafts.show"), resource_locator(@proposal).path, class: "button button__lg button__secondary w-full mt-4" %> -
diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal_cell.rb b/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal_cell.rb deleted file mode 100644 index ccf55af3df728..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_link_to_proposal_cell.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require "cell/partial" - -module Decidim - module Proposals - # This cell renders the link to the published proposal of a collaborative draft. - class CollaborativeDraftLinkToProposalCell < Decidim::ViewModel - def show - render if proposal - end - - private - - def proposal - @proposal ||= model.linked_resources(:proposal, "created_from_collaborative_draft").first - end - - def decidim - Decidim::Core::Engine.routes.url_helpers - end - - def decidim_proposals - Decidim::EngineRouter.main_proxy(model.component) - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_metadata_cell.rb b/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_metadata_cell.rb deleted file mode 100644 index 395a9a11e00fc..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_draft_metadata_cell.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # This cell renders metadata for an instance of a CollaborativeDraft - class CollaborativeDraftMetadataCell < Decidim::CardMetadataCell - include Decidim::Proposals::ApplicationHelper - - delegate :state, to: :model - - def initialize(*) - super - - @items.prepend(*collaborative_draft_items) - end - - private - - def collaborative_draft_items - [coauthors_item, comments_count_item, likes_count_item, state_item] - end - - def state_item - return if state.blank? - - { text: content_tag(:span, humanize_collaborative_draft_state(state), class: "label #{collaborative_drafts_state_class(state)}") } - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content/show.erb b/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content/show.erb deleted file mode 100644 index f8c12a0ae2a80..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content/show.erb +++ /dev/null @@ -1,3 +0,0 @@ -
-

<%= render_value model.body %>

-
diff --git a/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content_cell.rb b/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content_cell.rb deleted file mode 100644 index 52ce13762abc1..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/collaborative_drafts/reported_content_cell.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - module CollaborativeDrafts - # This cells renders a small preview of the `CollaborativeDraft` that is - # used in the moderations panel. - class ReportedContentCell < Decidim::ReportedContentCell - def show - render :show - end - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/irreversible_action_modal_cell.rb b/decidim-proposals/app/cells/decidim/proposals/irreversible_action_modal_cell.rb deleted file mode 100644 index d99915ff31ddd..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/irreversible_action_modal_cell.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # This cell renders the button and modal for the publish/withdraw - # actions in the details of a collaborative draft - # the `cell` should be called with an :action argument, to show relative info: - # - :publish - # - :withdraw - class IrreversibleActionModalCell < Decidim::ViewModel - def show - return unless action.presence - - render :show - end - - private - - def action - options[:action] - end - - def publish? - action == :publish - end - - def withdraw? - action == :withdraw - end - - def modal_id - @modal_id ||= "#{SecureRandom.uuid}-#{action}-irreversible-action-modal" - end - - def button_reveal_modal - data = { "dialog-open": modal_id } - label = t(action, scope: "decidim.proposals.collaborative_drafts.show") - css = publish? ? "button button__lg button__secondary w-full" : "text-secondary" - - button_tag label, type: "button", class: css, data: - end - - def modal_title - t("title", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal") - end - - def modal_body - t("body", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal") - end - - def button_continue - label = t("ok", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal") - path = resource_path action - css = "button button__lg button__secondary" - button_to label, path, class: css - end - - def close_label - t("cancel", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal") - end - - def button_cancel - button_tag type: "button", class: "button button__lg button__transparent-secondary", "data-dialog-close": modal_id do - close_label - end - end - - def resource_path(action) - @resource_path ||= decidim_proposals.send("#{action}_collaborative_draft_path", - id: model.id) - end - - def decidim_proposals - Decidim::EngineRouter.main_proxy(model.component) - end - end - end -end diff --git a/decidim-proposals/app/cells/decidim/proposals/proposal_link_to_collaborative_draft_cell.rb b/decidim-proposals/app/cells/decidim/proposals/proposal_link_to_collaborative_draft_cell.rb deleted file mode 100644 index 695767257a46c..0000000000000 --- a/decidim-proposals/app/cells/decidim/proposals/proposal_link_to_collaborative_draft_cell.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require "cell/partial" - -module Decidim - module Proposals - # This cell renders the link to the source collaborative draft of a proposal. - class ProposalLinkToCollaborativeDraftCell < ProposalLinkedResourcesCell - private - - def linked_resource - @linked_resource ||= model.linked_resources(:collaborative_draft, "created_from_collaborative_draft").first - end - - def link_to_resource_url - resource_locator(linked_resource).path - end - - def link_to_resource_text - t("link_to_collaborative_draft_text", scope: "decidim.proposals.proposals.show") - end - - def link_help_text - t("link_to_collaborative_draft_help_text", scope: "decidim.proposals.proposals.show") - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb deleted file mode 100644 index b41856cd0edac..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic to accept a user request to - # contribute to a collaborative draft. - class AcceptAccessToCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # form - A form object with the params. - # collaborative_draft - A Decidim::Proposals::CollaborativeDraft object. - # current_user - The current user. - # requester_user - The user that requested to collaborate. - def initialize(form, current_user) - @form = form - @collaborative_draft = form.collaborative_draft - @current_user = current_user - @requester_user = form.requester_user - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid. - # - :invalid if it was not valid and we could not proceed. - # - # Returns nothing. - def call - return broadcast(:invalid) if @form.invalid? - return broadcast(:invalid) if @current_user.nil? - - transaction do - @collaborative_draft.requesters.delete @requester_user - - Decidim::Coauthorship.create( - coauthorable: @collaborative_draft, - author: @requester_user - ) - end - - notify_collaborative_draft_requester - notify_collaborative_draft_authors - broadcast(:ok, @requester_user) - end - - private - - def notify_collaborative_draft_authors - affected_users = @collaborative_draft.notifiable_identities - [@requester_user] - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_access_accepted", - event_class: Decidim::Proposals::CollaborativeDraftAccessAcceptedEvent, - resource: @collaborative_draft, - affected_users: affected_users.uniq, - extra: { - requester_id: @requester_user.id - } - ) - end - - def notify_collaborative_draft_requester - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_access_requester_accepted", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequesterAcceptedEvent, - resource: @collaborative_draft, - affected_users: [@requester_user] - ) - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/admin/merge_proposals.rb b/decidim-proposals/app/commands/decidim/proposals/admin/merge_proposals.rb index 5d70da589393c..faac2a8144ceb 100644 --- a/decidim-proposals/app/commands/decidim/proposals/admin/merge_proposals.rb +++ b/decidim-proposals/app/commands/decidim/proposals/admin/merge_proposals.rb @@ -7,6 +7,7 @@ module Admin # one component to another. class MergeProposals < Decidim::Command include ::Decidim::MultipleAttachmentsMethods + # Public: Initializes the command. # # form - A form object with the params. diff --git a/decidim-proposals/app/commands/decidim/proposals/admin/update_proposal_taxonomies.rb b/decidim-proposals/app/commands/decidim/proposals/admin/update_proposal_taxonomies.rb index 85322bbc9fa7f..0f436615ce1c2 100644 --- a/decidim-proposals/app/commands/decidim/proposals/admin/update_proposal_taxonomies.rb +++ b/decidim-proposals/app/commands/decidim/proposals/admin/update_proposal_taxonomies.rb @@ -6,6 +6,7 @@ module Admin # A command with all the business logic when an admin batch updates proposals taxonomies. class UpdateProposalTaxonomies < UpdateResourcesTaxonomies include TranslatableAttributes + # Public: Initializes the command. # # taxonomy_ids - the taxonomy ids to update diff --git a/decidim-proposals/app/commands/decidim/proposals/create_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/create_collaborative_draft.rb deleted file mode 100644 index a436b7671c9e5..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/create_collaborative_draft.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic when a user creates a new collaborative draft. - class CreateCollaborativeDraft < Decidim::Command - include ::Decidim::MultipleAttachmentsMethods - - # Public: Initializes the command. - # - # form - A form object with the params. - # current_user - The current user. - def initialize(form, current_user) - @form = form - @current_user = current_user - @attached_to = nil - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid, together with the collaborative draft. - # - :invalid if the form was not valid and we could not proceed. - # - # Returns nothing. - def call - return broadcast(:invalid) if form.invalid? - - if process_attachments? - build_attachments - return broadcast(:invalid) if attachments_invalid? - end - - with_events(with_transaction: true) do - create_collaborative_draft - create_attachments if process_attachments? - end - - broadcast(:ok, collaborative_draft) - end - - private - - attr_reader :form, :collaborative_draft, :attachment - - def event_arguments - { - resource: collaborative_draft, - extra: { - event_author: form.current_user, - locale: - } - } - end - - def create_collaborative_draft - @collaborative_draft = Decidim.traceability.perform_action!( - :create, - CollaborativeDraft, - @form.current_user, - visibility: "public-only" - ) do - draft = CollaborativeDraft.new( - title: Decidim::ContentProcessor.parse(form.title, current_organization: form.current_organization).rewrite, - body: Decidim::ContentProcessor.parse_with_processor(:inline_images, form.body, current_organization: form.current_organization).rewrite, - taxonomizations: form.taxonomizations, - component: form.component, - address: form.address, - latitude: form.latitude, - longitude: form.longitude, - state: "open" - ) - draft.coauthorships.build(author: @current_user) - draft.save! - draft - end - - @attached_to = @collaborative_draft - end - - def organization - @organization ||= @current_user.organization - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/gallery_methods.rb b/decidim-proposals/app/commands/decidim/proposals/gallery_methods.rb index 9d22e3557be43..583bd8c118588 100644 --- a/decidim-proposals/app/commands/decidim/proposals/gallery_methods.rb +++ b/decidim-proposals/app/commands/decidim/proposals/gallery_methods.rb @@ -2,8 +2,7 @@ module Decidim module Proposals - # A module with all the gallery common methods for proposals - # and collaborative draft commands. + # A module with all the gallery common methods for proposals commands. # Allows to create several image attachments at once module GalleryMethods include ::Decidim::GalleryMethods diff --git a/decidim-proposals/app/commands/decidim/proposals/publish_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/publish_collaborative_draft.rb deleted file mode 100644 index da627adfdb047..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/publish_collaborative_draft.rb +++ /dev/null @@ -1,92 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic when a user publishes a collaborative_draft. - class PublishCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # collaborative_draft - The collaborative_draft to publish. - # current_user - The current user. - # proposal_form - the form object of the new proposal - def initialize(collaborative_draft, current_user) - @collaborative_draft = collaborative_draft - @current_user = current_user - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid and the collaborative_draft is published. - # - :invalid if the collaborative_draft's author is not the current user. - # - # Returns nothing. - def call - return broadcast(:invalid) unless @collaborative_draft.open? - return broadcast(:invalid) unless @collaborative_draft.authored_by? @current_user - - transaction do - reject_access_to_collaborative_draft - publish_collaborative_draft - create_proposal! - link_collaborative_draft_and_proposal - end - - broadcast(:ok, @new_proposal) - end - - attr_accessor :new_proposal - - private - - def reject_access_to_collaborative_draft - @collaborative_draft.requesters.each do |requester_user| - RejectAccessToCollaborativeDraft.call(@collaborative_draft, current_user, requester_user) - end - end - - def publish_collaborative_draft - Decidim.traceability.update!( - @collaborative_draft, - @current_user, - { state: "published", published_at: Time.current }, - visibility: "public-only" - ) - end - - def proposal_attributes - fields = {} - - parsed_title = Decidim::ContentProcessor.parse(@collaborative_draft.title, current_organization: @collaborative_draft.organization).rewrite - parsed_body = Decidim::ContentProcessor.parse_with_processor(:inline_images, @collaborative_draft.body, current_organization: @collaborative_draft.organization).rewrite - - fields[:title] = { I18n.locale => parsed_title } - fields[:body] = { I18n.locale => parsed_body } - fields[:component] = @collaborative_draft.component - fields[:address] = @collaborative_draft.address - fields[:published_at] = Time.current - - fields - end - - def create_proposal! - @new_proposal = Decidim.traceability.perform_action!( - :create, - Decidim::Proposals::Proposal, - @current_user, - visibility: "public-only" - ) do - new_proposal = Proposal.new(proposal_attributes) - new_proposal.coauthorships = @collaborative_draft.coauthorships - new_proposal.taxonomies = @collaborative_draft.taxonomies - new_proposal.attachments = @collaborative_draft.attachments - new_proposal.save! - new_proposal - end - end - - def link_collaborative_draft_and_proposal - @collaborative_draft.link_resources(@new_proposal, "created_from_collaborative_draft") - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb deleted file mode 100644 index 08d1ab4477ecb..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic to reject a user request to - # contribute to a collaborative draft. - class RejectAccessToCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # form - A form object with the params. - # collaborative_draft - A Decidim::Proposals::CollaborativeDraft object. - # current_user - The current user. - # requester_user - The user that requested to collaborate. - def initialize(form, current_user) - @form = form - @collaborative_draft = form.collaborative_draft - @current_user = current_user - @requester_user = form.requester_user - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid. - # - :invalid if it was not valid and we could not proceed. - # - # Returns nothing. - def call - return broadcast(:invalid) if @form.invalid? - return broadcast(:invalid) if @current_user.nil? - - @collaborative_draft.requesters.delete @requester_user - - notify_collaborative_draft_requester - notify_collaborative_draft_authors - broadcast(:ok, @requester_user) - end - - private - - def notify_collaborative_draft_authors - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_access_rejected", - event_class: Decidim::Proposals::CollaborativeDraftAccessRejectedEvent, - resource: @collaborative_draft, - affected_users: @collaborative_draft.authors, - extra: { - requester_id: @requester_user.id - } - ) - end - - def notify_collaborative_draft_requester - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_access_requester_rejected", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequesterRejectedEvent, - resource: @collaborative_draft, - affected_users: [@requester_user] - ) - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb deleted file mode 100644 index 2cd8004dbf128..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic when a user requests access - # to edit a collaborative draft. - class RequestAccessToCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # form - A form object with the params. - # collaborative_draft - A Decidim::Proposals::CollaborativeDraft object. - # current_user - The current user and requester user - def initialize(form, current_user) - @form = form - @collaborative_draft = form.collaborative_draft - @current_user = current_user - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid. - # - :invalid if it was not valid and we could not proceed. - # - # Returns nothing. - def call - return broadcast(:invalid) if @form.invalid? - return broadcast(:invalid) if @current_user.nil? - - @collaborative_draft.collaborator_requests.create!(user: @current_user) - notify_collaborative_draft_authors - broadcast(:ok, @collaborative_draft) - end - - private - - def notify_collaborative_draft_authors - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_access_requested", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequestedEvent, - resource: @collaborative_draft, - affected_users: @collaborative_draft.authors, - extra: { - requester_id: @current_user.id - } - ) - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/update_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/update_collaborative_draft.rb deleted file mode 100644 index 1f28e4106c342..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/update_collaborative_draft.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic when a user updates a collaborative_draft. - class UpdateCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # form - A form object with the params. - # current_user - The current user. - # collaborative_draft - the collaborative_draft to update. - def initialize(form, current_user, collaborative_draft) - @form = form - @current_user = current_user - @collaborative_draft = collaborative_draft - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid, together with the collaborative_draft. - # - :invalid if the form was not valid and we could not proceed. - # - # Returns nothing. - def call - return broadcast(:invalid) if form.invalid? - return broadcast(:invalid) unless collaborative_draft.editable_by?(current_user) - - with_events(with_transaction: true) do - update_collaborative_draft - end - - broadcast(:ok, collaborative_draft) - end - - private - - attr_reader :form, :collaborative_draft, :current_user - - def event_arguments - { - resource: collaborative_draft, - extra: { - event_author: form.current_user, - locale: - } - } - end - - def update_collaborative_draft - Decidim.traceability.update!( - @collaborative_draft, - @current_user, - attributes, - visibility: "public-only" - ) - end - - def attributes - { - title: Decidim::ContentProcessor.parse(form.title, current_organization: form.current_organization).rewrite, - body: Decidim::ContentProcessor.parse_with_processor(:inline_images, form.body, current_organization: form.current_organization).rewrite, - taxonomizations: form.taxonomizations, - address: form.address, - latitude: form.latitude, - longitude: form.longitude - } - end - end - end -end diff --git a/decidim-proposals/app/commands/decidim/proposals/withdraw_collaborative_draft.rb b/decidim-proposals/app/commands/decidim/proposals/withdraw_collaborative_draft.rb deleted file mode 100644 index 0ecb74c2ea20b..0000000000000 --- a/decidim-proposals/app/commands/decidim/proposals/withdraw_collaborative_draft.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A command with all the business logic when a user withdraws a collaborative_draft. - class WithdrawCollaborativeDraft < Decidim::Command - # Public: Initializes the command. - # - # collaborative_draft - The collaborative_draft to withdraw. - # current_user - The current user. - def initialize(collaborative_draft, current_user) - @collaborative_draft = collaborative_draft - @current_user = current_user - end - - # Executes the command. Broadcasts these events: - # - # - :ok when everything is valid and the collaborative_draft is published. - # - :invalid if the collaborative_draft's author is not the current user. - # - # Returns nothing. - def call - return broadcast(:invalid) if @collaborative_draft.withdrawn? - return broadcast(:invalid) if @collaborative_draft.published? - return broadcast(:invalid) unless @collaborative_draft.authored_by? @current_user - - transaction do - @collaborative_draft.requesters.each do |requester_user| - RejectAccessToCollaborativeDraft.call(@collaborative_draft, current_user, requester_user) - end - - withdraw_collaborative_draft - send_notification_to_authors - end - - broadcast(:ok, @collaborative_draft) - end - - private - - def withdraw_collaborative_draft - Decidim.traceability.update!( - @collaborative_draft, - @current_user, - state: "withdrawn" - ) - end - - def send_notification_to_authors - recipients = @collaborative_draft.authors - [@current_user] - return if recipients.blank? - - Decidim::EventsManager.publish( - event: "decidim.events.proposals.collaborative_draft_withdrawn", - event_class: Decidim::Proposals::CollaborativeDraftWithdrawnEvent, - resource: @collaborative_draft, - affected_users: recipients.uniq, - extra: { - author_id: @current_user.id - } - ) - end - end - end -end diff --git a/decidim-proposals/app/controllers/concerns/decidim/proposals/orderable.rb b/decidim-proposals/app/controllers/concerns/decidim/proposals/orderable.rb index f5ea177cf03a7..1295715fcd39b 100644 --- a/decidim-proposals/app/controllers/concerns/decidim/proposals/orderable.rb +++ b/decidim-proposals/app/controllers/concerns/decidim/proposals/orderable.rb @@ -22,8 +22,8 @@ def possible_orders @possible_orders ||= begin possible_orders = %w(random recent) possible_orders << "most_voted" if most_voted_order_available? - possible_orders << "most_liked" if current_settings.likes_enabled? - possible_orders << "most_commented" if component_settings.comments_enabled? + possible_orders << "most_liked" if most_liked_order_available? + possible_orders << "most_commented" if most_commented_order_available? possible_orders << "most_followed" possible_orders << "with_more_authors" if with_more_authors_order_available? possible_orders @@ -59,6 +59,18 @@ def with_more_authors_order_available? @with_more_authors_order_available = Decidim::Proposals::Proposal.with_more_authors_available?(current_component) end + def most_commented_order_available? + return @most_commented_order_available if defined?(@most_commented_order_available) + + @most_commented_order_available = Decidim::Proposals::Proposal.most_commented_available?(current_component) + end + + def most_liked_order_available? + return @most_liked_order_available if defined?(@most_liked_order_available) + + @most_liked_order_available = Decidim::Proposals::Proposal.most_liked_available?(current_component) + end + def order_by_votes? most_voted_order_available? && current_settings.votes_blocked? end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb index ffeb056e68dd6..b3a570b95f129 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb @@ -34,12 +34,12 @@ def destroy Admin::UnassignProposalsFromEvaluator.call(@form) do on(:ok) do |_proposal| flash.keep[:notice] = I18n.t("evaluation_assignments.delete.success", scope: "decidim.proposals.admin") - redirect_back fallback_location: EngineRouter.admin_proxy(current_component).root_path + redirect_back_or_to(EngineRouter.admin_proxy(current_component).root_path) end on(:invalid) do flash.keep[:alert] = I18n.t("evaluation_assignments.delete.invalid", scope: "decidim.proposals.admin") - redirect_back fallback_location: EngineRouter.admin_proxy(current_component).root_path + redirect_back_or_to(EngineRouter.admin_proxy(current_component).root_path) end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb index c715f72b7ff8f..c4d4ab07aff93 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb @@ -32,12 +32,12 @@ def import on(:invalid) do flash.now[:alert] = I18n.t("participatory_texts.import.invalid", scope: "decidim.proposals.admin") - render action: "new_import", status: :unprocessable_entity + render action: "new_import", status: :unprocessable_content end on(:invalid_file) do flash.now[:alert] = I18n.t("participatory_texts.import.invalid_file", scope: "decidim.proposals.admin") - render action: "new_import", status: :unprocessable_entity + render action: "new_import", status: :unprocessable_content end end end @@ -62,7 +62,7 @@ def update failures.each_pair { |id, msg| alert_msg << "ID:[#{id}] #{msg}" } flash.now[:alert] = alert_msg.join("
").html_safe index - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end else @@ -77,7 +77,7 @@ def update failures.each_pair { |id, msg| alert_msg << "ID:[#{id}] #{msg}" } flash.now[:alert] = alert_msg.join("
").html_safe index - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb index f8f8a12ba4f1a..e5672b60b79aa 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb @@ -34,7 +34,7 @@ def update on(:invalid) do flash.keep[:alert] = I18n.t("proposals.answer.invalid", scope: "decidim.proposals.admin") - render template: "decidim/proposals/admin/proposals/show", status: :unprocessable_entity + render template: "decidim/proposals/admin/proposals/show", status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_states_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_states_controller.rb index 7320fdaaa3e6a..51d91aca679cc 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_states_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/proposal_states_controller.rb @@ -30,7 +30,7 @@ def create on(:invalid) do flash.keep[:alert] = I18n.t("proposal_states.create.error", scope: "decidim.proposals.admin") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end @@ -54,7 +54,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("proposal_states.update.error", scope: "decidim.proposals.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb index 4152d0253c827..6c6852cd4f9a0 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb @@ -44,7 +44,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("proposals.create.invalid", scope: "decidim.proposals.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -129,7 +129,7 @@ def update on(:invalid) do flash.now[:alert] = t("proposals.update.error", scope: "decidim") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb index 20f54c5a6c4c7..d3c1ccc67f808 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb @@ -23,10 +23,25 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("proposals_imports.create.invalid", scope: "decidim.proposals.admin") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end + + def component_states + enforce_permission_to :import, :proposals + component = current_participatory_space.components.find_by(id: params[:origin_id]) + + if component + states = Decidim::Proposals::ProposalState + .where(component:) + .map { |s| { token: s.token, title: translated_attribute(s.title) } } + states << { token: "not_answered", title: I18n.t("decidim.proposals.answers.not_answered") } + render json: states + else + render json: [] + end + end end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb index 8aa84e0553708..9fb6b84329d47 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb @@ -29,7 +29,7 @@ def create I18n.t("proposals_merges.create.invalid", scope: "decidim.proposals.admin"), @form ).message - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller.rb deleted file mode 100644 index e8bf86da7764f..0000000000000 --- a/decidim-proposals/app/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # Exposes Collaborative Draft Request actions for collaboration between - # participants on a resource. - class CollaborativeDraftCollaboratorRequestsController < Decidim::Proposals::CollaborativeDraftsController - before_action :retrieve_collaborative_draft, only: [:request_access, :request_accept, :request_reject] - - def request_access - @request_access_form = form(RequestAccessToCollaborativeDraftForm).from_params(params) - RequestAccessToCollaborativeDraft.call(@request_access_form, current_user) do - on(:ok) do |_collaborative_draft| - flash[:notice] = t("access_requested.success", scope: "decidim.proposals.collaborative_drafts.requests") - end - - on(:invalid) do - flash[:alert] = t("access_requested.error", scope: "decidim.proposals.collaborative_drafts.requests") - end - end - redirect_to Decidim::ResourceLocatorPresenter.new(@collaborative_draft).path - end - - def request_accept - @accept_request_form = form(AcceptAccessToCollaborativeDraftForm).from_params(params) - AcceptAccessToCollaborativeDraft.call(@accept_request_form, current_user) do - on(:ok) do |requester_user| - flash[:notice] = t("accepted_request.success", scope: "decidim.proposals.collaborative_drafts.requests", user: requester_user.nickname) - end - - on(:invalid) do - flash[:alert] = t("accepted_request.error", scope: "decidim.proposals.collaborative_drafts.requests") - end - end - redirect_to Decidim::ResourceLocatorPresenter.new(@collaborative_draft).path - end - - def request_reject - @reject_request_form = form(RejectAccessToCollaborativeDraftForm).from_params(params) - RejectAccessToCollaborativeDraft.call(@reject_request_form, current_user) do - on(:ok) do |requester_user| - flash[:notice] = t("rejected_request.success", scope: "decidim.proposals.collaborative_drafts.requests", user: requester_user.nickname) - end - - on(:invalid) do - flash.now[:alert] = t("rejected_request.error", scope: "decidim.proposals.collaborative_drafts.requests") - end - end - redirect_to Decidim::ResourceLocatorPresenter.new(@collaborative_draft).path - end - end - end -end diff --git a/decidim-proposals/app/controllers/decidim/proposals/collaborative_drafts_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/collaborative_drafts_controller.rb deleted file mode 100644 index d20d3aa2e18f6..0000000000000 --- a/decidim-proposals/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +++ /dev/null @@ -1,152 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # Exposes Collaborative Drafts resource so users can view and create them. - class CollaborativeDraftsController < Decidim::Proposals::ApplicationController - helper ProposalWizardHelper - helper TooltipHelper - - include Decidim::ApplicationHelper - include Decidim::IconHelper - include FormFactory - include Flaggable - include FilterResource - include CollaborativeOrderable - include Paginable - - helper_method :form_presenter - - helper_method :geocoded_collaborative_draft, :collaborative_draft - before_action :collaborative_drafts_enabled? - before_action :authenticate_user!, only: [:new, :create] - before_action :retrieve_collaborative_draft, only: [:show, :edit, :update, :withdraw, :publish] - - def index - @collaborative_drafts = search - .result - .not_hidden - .includes(:taxonomies) - - @collaborative_drafts = reorder(@collaborative_drafts) - @collaborative_drafts = paginate(@collaborative_drafts) - end - - def show - raise ActionController::RoutingError, "Not Found" unless retrieve_collaborative_draft - - @request_access_form = form(RequestAccessToCollaborativeDraftForm).from_params({}) - @accept_request_form = form(AcceptAccessToCollaborativeDraftForm).from_params({}) - @reject_request_form = form(RejectAccessToCollaborativeDraftForm).from_params({}) - end - - def new - enforce_permission_to :create, :collaborative_draft - - @form = form(CollaborativeDraftForm).from_params( - attachment: form(AttachmentForm).from_params({}) - ) - end - - def create - enforce_permission_to :create, :collaborative_draft - @form = form(CollaborativeDraftForm).from_params(params) - - CreateCollaborativeDraft.call(@form, current_user) do - on(:ok) do |collaborative_draft| - flash[:notice] = I18n.t("proposals.collaborative_drafts.create.success", scope: "decidim") - - redirect_to Decidim::ResourceLocatorPresenter.new(collaborative_draft).path - end - - on(:invalid) do - flash.now[:alert] = I18n.t("proposals.collaborative_drafts.create.error", scope: "decidim") - render :new, status: :unprocessable_entity - end - end - end - - def edit - enforce_permission_to :edit, :collaborative_draft, collaborative_draft: @collaborative_draft - - @form = form(CollaborativeDraftForm).from_model(@collaborative_draft) - @form.attachment = form(AttachmentForm).from_model(@collaborative_draft.attachments.first) - end - - def update - enforce_permission_to :edit, :collaborative_draft, collaborative_draft: @collaborative_draft - - @form = form(CollaborativeDraftForm).from_params(params) - UpdateCollaborativeDraft.call(@form, current_user, @collaborative_draft) do - on(:ok) do |collaborative_draft| - flash[:notice] = I18n.t("proposals.collaborative_drafts.update.success", scope: "decidim") - redirect_to Decidim::ResourceLocatorPresenter.new(collaborative_draft).path - end - - on(:invalid) do - flash.now[:alert] = I18n.t("proposals.collaborative_drafts.update.error", scope: "decidim") - render :edit, status: :unprocessable_entity - end - end - end - - def withdraw - WithdrawCollaborativeDraft.call(@collaborative_draft, current_user) do - on(:ok) do - flash[:notice] = t("withdraw.success", scope: "decidim.proposals.collaborative_drafts.collaborative_draft") - end - - on(:invalid) do - flash.now[:alert] = t("withdraw.error", scope: "decidim.proposals.collaborative_drafts.collaborative_draft") - end - end - redirect_to Decidim::ResourceLocatorPresenter.new(@collaborative_draft).path - end - - def publish - PublishCollaborativeDraft.call(@collaborative_draft, current_user) do - on(:ok) do |proposal| - flash[:notice] = I18n.t("publish.success", scope: "decidim.proposals.collaborative_drafts.collaborative_draft") - redirect_to Decidim::ResourceLocatorPresenter.new(proposal).path - end - - on(:invalid) do - flash.now[:alert] = t("publish.error", scope: "decidim.proposals.collaborative_drafts.collaborative_draft") - redirect_to Decidim::ResourceLocatorPresenter.new(@collaborative_draft).path - end - end - end - - private - - def form_presenter - @form_presenter ||= present(@form, presenter_class: Decidim::Proposals::CollaborativeDraftPresenter) - end - - def collaborative_drafts_enabled? - raise ActionController::RoutingError, "Not Found" unless component_settings.collaborative_drafts_enabled? - end - - def retrieve_collaborative_draft - @collaborative_draft = CollaborativeDraft.not_hidden.where(component: current_component).find_by(id: params[:id]) - end - - def geocoded_collaborative_draft - @geocoded_collaborative_draft ||= search.result.not_hidden.select(&:geocoded_and_valid?) - end - - def search_collection - CollaborativeDraft.where(component: current_component).not_hidden - end - - def default_filter_params - { - search_text_cont: "", - with_any_taxonomies: nil, - with_any_state: %w(open), - related_to: "" - } - end - end - end -end diff --git a/decidim-proposals/app/controllers/decidim/proposals/invite_coauthors_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/invite_coauthors_controller.rb index 6d0c022d40871..ba78b9589541e 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/invite_coauthors_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/invite_coauthors_controller.rb @@ -53,7 +53,7 @@ def update end on(:invalid) do - render json: { message: I18n.t("update.error", scope: "decidim.proposals.invite_coauthors") }, status: :unprocessable_entity + render json: { message: I18n.t("update.error", scope: "decidim.proposals.invite_coauthors") }, status: :unprocessable_content end end end @@ -68,7 +68,7 @@ def destroy end on(:invalid) do - render json: { message: I18n.t("destroy.error", scope: "decidim.proposals.invite_coauthors") }, status: :unprocessable_entity + render json: { message: I18n.t("destroy.error", scope: "decidim.proposals.invite_coauthors") }, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/proposal_votes_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/proposal_votes_controller.rb index 471fff8767574..2c1b2a3272c86 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/proposal_votes_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/proposal_votes_controller.rb @@ -29,7 +29,7 @@ def create end on(:invalid) do - render json: { error: I18n.t("proposal_votes.create.error", scope: "decidim.proposals") }, status: :unprocessable_entity + render json: { error: I18n.t("proposal_votes.create.error", scope: "decidim.proposals") }, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/proposals_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/proposals_controller.rb index 9f9b664323b35..d37b7fb0746f3 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/proposals_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/proposals_controller.rb @@ -79,7 +79,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("proposals.create.error", scope: "decidim") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -101,7 +101,7 @@ def publish on(:invalid) do flash.now[:alert] = I18n.t("proposals.publish.error", scope: "decidim") - render :edit_draft, status: :unprocessable_entity + render :edit_draft, status: :unprocessable_content end end end @@ -124,7 +124,7 @@ def update_draft on(:invalid) do flash.now[:alert] = I18n.t("proposals.update_draft.error", scope: "decidim") - render :edit_draft, status: :unprocessable_entity + render :edit_draft, status: :unprocessable_content end end end @@ -140,7 +140,7 @@ def destroy_draft on(:invalid) do flash.now[:alert] = I18n.t("proposals.destroy_draft.error", scope: "decidim") - render :edit_draft, status: :unprocessable_entity + render :edit_draft, status: :unprocessable_content end end end @@ -161,7 +161,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("proposals.update.error", scope: "decidim") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-proposals/app/controllers/decidim/proposals/versions_controller.rb b/decidim-proposals/app/controllers/decidim/proposals/versions_controller.rb index 7529ca3880f97..b67d80a89b574 100644 --- a/decidim-proposals/app/controllers/decidim/proposals/versions_controller.rb +++ b/decidim-proposals/app/controllers/decidim/proposals/versions_controller.rb @@ -2,19 +2,13 @@ module Decidim module Proposals - # Exposes Proposals versions so users can see how a Proposal/CollaborativeDraft - # has been updated through time. + # Exposes Proposals versions so users can see how a Proposal has been updated through time. class VersionsController < Decidim::Proposals::ApplicationController include Decidim::ApplicationHelper include Decidim::ResourceVersionsConcern def versioned_resource - @versioned_resource ||= - if params[:proposal_id] - Proposal.not_hidden.published.where(component: current_component).find(params[:proposal_id]) - else - CollaborativeDraft.where(component: current_component).find(params[:collaborative_draft_id]) - end + @versioned_resource ||= Proposal.not_hidden.published.where(component: current_component).find(params[:proposal_id]) end def add_breadcrumb_item diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_accepted_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_accepted_event.rb deleted file mode 100644 index 07c4186e75fdd..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_accepted_event.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessAcceptedEvent < CollaborativeDraftAccessRequestEvent - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_rejected_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_rejected_event.rb deleted file mode 100644 index 8b8b6e3018af1..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_rejected_event.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessRejectedEvent < CollaborativeDraftAccessRequestEvent - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_request_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_request_event.rb deleted file mode 100644 index 2f59f04d680da..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_request_event.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessRequestEvent < Decidim::Events::SimpleEvent - i18n_attributes :requester_name, :requester_path, :requester_nickname - - delegate :name, to: :requester, prefix: true - - delegate :nickname, to: :requester, prefix: true - - def requester_path - requester.profile_path - end - - private - - def requester - @requester ||= Decidim::UserPresenter.new(rejected_requester_user) - end - - def rejected_requester_user - @rejected_requester_user ||= Decidim::User.find_by(id: extra[:requester_id]) - end - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requested_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requested_event.rb deleted file mode 100644 index 267d1940535dc..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requested_event.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessRequestedEvent < CollaborativeDraftAccessRequestEvent - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_accepted_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_accepted_event.rb deleted file mode 100644 index 1a1ca2412b77c..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_accepted_event.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessRequesterAcceptedEvent < Decidim::Events::SimpleEvent - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_rejected_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_rejected_event.rb deleted file mode 100644 index 48874875c57aa..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_access_requester_rejected_event.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftAccessRequesterRejectedEvent < Decidim::Events::SimpleEvent - end - end -end diff --git a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_withdrawn_event.rb b/decidim-proposals/app/events/decidim/proposals/collaborative_draft_withdrawn_event.rb deleted file mode 100644 index 52426e7d0ec4f..0000000000000 --- a/decidim-proposals/app/events/decidim/proposals/collaborative_draft_withdrawn_event.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftWithdrawnEvent < Decidim::Events::SimpleEvent - i18n_attributes :author_nickname, :author_name, :author_path, :author_url - - delegate :nickname, :name, to: :author, prefix: true - - def nickname - author_nickname - end - - def author_path - author.profile_path - end - - def author_url - author.profile_url - end - - private - - def author - @author ||= Decidim::UserPresenter.new(author_user) - end - - def author_user - @author_user ||= Decidim::User.find_by(id: extra[:author_id]) - end - end - end -end diff --git a/decidim-proposals/app/forms/decidim/proposals/accept_access_to_collaborative_draft_form.rb b/decidim-proposals/app/forms/decidim/proposals/accept_access_to_collaborative_draft_form.rb deleted file mode 100644 index 8a70efa4b4d09..0000000000000 --- a/decidim-proposals/app/forms/decidim/proposals/accept_access_to_collaborative_draft_form.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A form object to be used when Collaborative Draft editors accept a request - # to access it as coauthors. - class AcceptAccessToCollaborativeDraftForm < AccessToCollaborativeDraftForm - end - end -end diff --git a/decidim-proposals/app/forms/decidim/proposals/access_to_collaborative_draft_form.rb b/decidim-proposals/app/forms/decidim/proposals/access_to_collaborative_draft_form.rb deleted file mode 100644 index d2803a1eb7cbd..0000000000000 --- a/decidim-proposals/app/forms/decidim/proposals/access_to_collaborative_draft_form.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A form object common to accept and reject actions requesters of Collaborative Drafts. - class AccessToCollaborativeDraftForm < Decidim::Form - mimic :collaborative_draft - - attribute :id, String - attribute :requester_user_id, String - attribute :state, String - - validates :id, :requester_user_id, presence: true - validates :state, presence: true, inclusion: { in: %w(open) } - - validate :existence_of_requester_in_requesters - - def collaborative_draft - @collaborative_draft ||= Decidim::Proposals::CollaborativeDraft.find id if id - end - - def requester_user - @requester_user ||= Decidim::User.find_by(id: requester_user_id, organization: current_organization) if requester_user_id - end - - private - - def existence_of_requester_in_requesters - errors.add(:requester_user_id, :invalid) if collaborative_draft && !collaborative_draft.requesters.exists?(requester_user_id) - end - end - end -end diff --git a/decidim-proposals/app/forms/decidim/proposals/admin/proposal_form.rb b/decidim-proposals/app/forms/decidim/proposals/admin/proposal_form.rb index 35fbfaaaf589a..f4d392a9d53f6 100644 --- a/decidim-proposals/app/forms/decidim/proposals/admin/proposal_form.rb +++ b/decidim-proposals/app/forms/decidim/proposals/admin/proposal_form.rb @@ -27,12 +27,62 @@ def map_model(model) self.title = presenter.title(all_locales: title.is_a?(Hash)) self.body = presenter.editor_body(all_locales: body.is_a?(Hash)) - self.documents = model.attachments + self.documents = model.attachments.ids + self.add_documents = model.attachments.map { |att| { id: att.id, title: att.title } } + end + + def documents=(value) + case value + when String + super(parse_string_documents(value)) + when Integer + super([value]) + else + super + end + end + + def documents + result = super + + if should_use_add_documents?(result) + extract_ids_from_add_documents + else + result.is_a?(Array) ? result : [] + end end def notify_missing_attachment_if_errored errors.add(:add_documents, :needs_to_be_reattached) if errors.any? && add_documents.present? end + + private + + def should_use_add_documents?(result) + (result.blank? || result.is_a?(String)) && add_documents.present? + end + + def extract_ids_from_add_documents + add_documents + .select { |doc| doc.is_a?(Hash) && (doc[:id].present? || doc["id"].present?) } + .map { |doc| (doc[:id] || doc["id"]).to_i } + end + + def parse_string_documents(value) + return [] if value.blank? + + parse_document_ids(value) + end + + def parse_document_ids(value) + ids = begin + Array(JSON.parse(value)) + rescue JSON::ParserError + value.split(",").map(&:strip) + end + + ids.map(&:to_i).reject(&:zero?) + end end end end diff --git a/decidim-proposals/app/forms/decidim/proposals/admin/proposals_import_form.rb b/decidim-proposals/app/forms/decidim/proposals/admin/proposals_import_form.rb index 47010b4acfc5c..765eba828bb6a 100644 --- a/decidim-proposals/app/forms/decidim/proposals/admin/proposals_import_form.rb +++ b/decidim-proposals/app/forms/decidim/proposals/admin/proposals_import_form.rb @@ -7,6 +7,7 @@ module Admin # from another component. class ProposalsImportForm < Decidim::Form include TranslatableAttributes + mimic :proposals_import attribute :origin_component_id, Integer @@ -14,16 +15,10 @@ class ProposalsImportForm < Decidim::Form attribute :keep_authors, Boolean attribute :states, Array[String] - validates :origin_component_id, :origin_component, :states, :current_component, presence: true + validates :origin_component_id, :origin_component, :current_component, presence: true + validates :states, presence: true validate :valid_states - def states_collection - @states_collection ||= ProposalState.where(component: current_component) + [ProposalState.new(token: "not_answered", - title: I18n.t( - :not_answered, scope: "decidim.proposals.answers" - ))] - end - def states super.compact_blank end @@ -42,23 +37,14 @@ def origin_components_collection end end - def available_states(component_id = nil) - scope = Decidim::Proposals::ProposalState - scope = scope.where(component: Decidim::Component.find(component_id)) if component_id.present? - - states = scope.pluck(:token).uniq.map do |token| - OpenStruct.new(token:, title: token.humanize) - end - - states + [OpenStruct.new(token: "not_answered", title: I18n.t("decidim.proposals.answers.not_answered"))] - end - private def valid_states - return if states.all? do |state| - available_states(origin_component_id).pluck(:token).include?(state) - end + return unless origin_component + return if states.empty? + + valid_tokens = Decidim::Proposals::ProposalState.where(component: origin_component).pluck(:token) + ["not_answered"] + return if states.all? { |state| valid_tokens.include?(state) } errors.add(:states, :invalid) end diff --git a/decidim-proposals/app/forms/decidim/proposals/admin/proposals_merge_form.rb b/decidim-proposals/app/forms/decidim/proposals/admin/proposals_merge_form.rb index e3ce715b6dd8a..e7ade3549d2e5 100644 --- a/decidim-proposals/app/forms/decidim/proposals/admin/proposals_merge_form.rb +++ b/decidim-proposals/app/forms/decidim/proposals/admin/proposals_merge_form.rb @@ -8,6 +8,7 @@ module Admin class ProposalsMergeForm < ProposalBaseForm include Decidim::HasUploadValidations include Decidim::AttachmentAttributes + translatable_attribute :title, String do |field, _locale| validates field, length: { in: 15..150 }, if: proc { |resource| resource.send(field).present? } end diff --git a/decidim-proposals/app/forms/decidim/proposals/collaborative_draft_form.rb b/decidim-proposals/app/forms/decidim/proposals/collaborative_draft_form.rb deleted file mode 100644 index e27f06659e898..0000000000000 --- a/decidim-proposals/app/forms/decidim/proposals/collaborative_draft_form.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A form object to be used when public users want to create a Collaborative Draft. - class CollaborativeDraftForm < Decidim::Proposals::ProposalForm; end - end -end diff --git a/decidim-proposals/app/forms/decidim/proposals/reject_access_to_collaborative_draft_form.rb b/decidim-proposals/app/forms/decidim/proposals/reject_access_to_collaborative_draft_form.rb deleted file mode 100644 index 981224c0e5bef..0000000000000 --- a/decidim-proposals/app/forms/decidim/proposals/reject_access_to_collaborative_draft_form.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A form object to be used when Collaborative Draft editors rejects a request to access it. - class RejectAccessToCollaborativeDraftForm < AccessToCollaborativeDraftForm - end - end -end diff --git a/decidim-proposals/app/forms/decidim/proposals/request_access_to_collaborative_draft_form.rb b/decidim-proposals/app/forms/decidim/proposals/request_access_to_collaborative_draft_form.rb deleted file mode 100644 index 807ec8061879b..0000000000000 --- a/decidim-proposals/app/forms/decidim/proposals/request_access_to_collaborative_draft_form.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A form object to be used when public users want to request access to a Collaborative Draft. - class RequestAccessToCollaborativeDraftForm < Decidim::Form - mimic :collaborative_draft - - attribute :id, String - attribute :state, String - - validates :id, presence: true - validates :state, presence: true, inclusion: { in: %w(open) } - - def collaborative_draft - @collaborative_draft ||= Decidim::Proposals::CollaborativeDraft.find id - end - end - end -end diff --git a/decidim-proposals/app/helpers/decidim/proposals/application_helper.rb b/decidim-proposals/app/helpers/decidim/proposals/application_helper.rb index 20a1cd8446da4..91d58be7bd1ee 100644 --- a/decidim-proposals/app/helpers/decidim/proposals/application_helper.rb +++ b/decidim-proposals/app/helpers/decidim/proposals/application_helper.rb @@ -12,7 +12,6 @@ module ApplicationHelper include ::Decidim::FollowableHelper include Decidim::MapHelper include Decidim::Proposals::MapHelper - include CollaborativeDraftHelper include ControlVersionHelper include Decidim::RichTextEditorHelper include Decidim::CheckBoxesTreeHelper @@ -54,49 +53,19 @@ def proposal_state_css_class(proposal) end end - # Public: The state of a proposal in a way a human can understand. - # - # state - The String state of the proposal. - # - # Returns a String. - def humanize_collaborative_draft_state(state) - I18n.t("decidim.proposals.collaborative_drafts.states.#{state}", default: :open) - end - - # Public: The css class applied based on the collaborative draft state. - # - # state - The String state of the collaborative draft. - # - # Returns a String. - def collaborative_draft_state_badge_css_class(state) - case state - when "open" - "success" - when "withdrawn" - "alert" - when "published" - "secondary" - end - end - def proposal_limit_enabled? proposal_limit.present? end - def not_from_collaborative_draft(proposal) - proposal.linked_resources(:proposals, "created_from_collaborative_draft").empty? - end - def not_from_participatory_text(proposal) proposal.participatory_text_level.nil? end # If the proposal is official or the rich text editor is enabled on the # frontend, the proposal body is considered as safe content; that is unless - # the proposal comes from a collaborative_draft or a participatory_text. + # safe_content_admin? is used and the proposal comes from a participatory text. def safe_content? - (rich_text_editor_in_public_views? && not_from_collaborative_draft(@proposal)) || - safe_content_admin? + rich_text_editor_in_public_views? || safe_content_admin? end # For admin entered content, the proposal body can contain certain extra @@ -252,7 +221,7 @@ def filter_sections end def component_name - i18n_key = controller_name == "collaborative_drafts" ? "decidim.proposals.collaborative_drafts.name" : "decidim.components.proposals.name" + i18n_key = "decidim.components.proposals.name" (defined?(current_component) && translated_attribute(current_component&.name).presence) || t(i18n_key) end diff --git a/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_cells_helper.rb b/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_cells_helper.rb deleted file mode 100644 index 62a3a6a738d6b..0000000000000 --- a/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_cells_helper.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # Custom helpers, scoped to the proposals engine. - # - module CollaborativeDraftCellsHelper - include Decidim::Proposals::ApplicationHelper - include Decidim::Proposals::Engine.routes.url_helpers - include Decidim::LayoutHelper - include Decidim::ApplicationHelper - include Decidim::TranslationsHelper - include Decidim::ResourceReferenceHelper - include Decidim::TranslatableAttributes - include Decidim::CardHelper - - delegate :title, :state, to: :model - - def has_actions? - false - end - - def current_settings - model.component.current_settings - end - - def component_settings - model.component.settings - end - - def current_component - model.component - end - - def from_context - @options[:from] - end - - def badge_name - humanize_collaborative_draft_state state - end - - def state_classes - [collaborative_draft_state_badge_css_class(state).to_s] - end - end - end -end diff --git a/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_helper.rb b/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_helper.rb deleted file mode 100644 index ed3dcfebb978f..0000000000000 --- a/decidim-proposals/app/helpers/decidim/proposals/collaborative_draft_helper.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # Custom helpers, scoped to the collaborative_draft resource. - # - module CollaborativeDraftHelper - def filter_collaborative_drafts_state_values - scope = "decidim.proposals.collaborative_drafts.filters" - Decidim::CheckBoxesTreeHelper::TreeNode.new( - Decidim::CheckBoxesTreeHelper::TreePoint.new("", t("all", scope:)), - [ - Decidim::CheckBoxesTreeHelper::TreePoint.new("open", t("open", scope:)), - Decidim::CheckBoxesTreeHelper::TreePoint.new("withdrawn", t("withdrawn", scope:)), - Decidim::CheckBoxesTreeHelper::TreePoint.new("published", t("published", scope:)) - ] - ) - end - - def humanize_collaborative_draft_state(state) - I18n.t(state, scope: "decidim.proposals.collaborative_drafts.states", default: :open) - end - - def collaborative_drafts_state_class(type) - case type - when "withdrawn" - "alert" - when "open", "published" - "success" - end - end - - def accept_request_button_label - t("accept_request", scope: "decidim.proposals.collaborative_drafts.requests.collaboration_requests") - end - - def reject_request_button_label - t("reject_request", scope: "decidim.proposals.collaborative_drafts.requests.collaboration_requests") - end - - def collaborative_drafts_filter_sections - @collaborative_drafts_filter_sections ||= begin - items = [{ - method: :with_any_state, - name: "[with_any_state]", - collection: filter_collaborative_drafts_state_values, - label: t("decidim.proposals.collaborative_drafts.filters.state"), - id: "state" - }] - current_component.available_taxonomy_filters.each do |taxonomy_filter| - items.append(method: :with_any_taxonomies, - name: "[with_any_taxonomies][#{taxonomy_filter.root_taxonomy_id}]", - collection: filter_taxonomy_values_for(taxonomy_filter), - label: decidim_sanitize_translated(taxonomy_filter.name), - id: "taxonomy-#{taxonomy_filter.root_taxonomy_id}") - end - if linked_classes_for(Decidim::Proposals::CollaborativeDraft).any? - items.append( - method: :related_to, - name: "[related_to]", - collection: linked_classes_filter_values_for(Decidim::Proposals::CollaborativeDraft), - label: t("decidim.proposals.collaborative_drafts.filters.related_to"), - id: "related_to", - type: :radio_buttons - ) - end - items.reject { |item| item[:collection].blank? } - end - end - end - end -end diff --git a/decidim-proposals/app/jobs/decidim/proposals/hide_all_created_by_author_job.rb b/decidim-proposals/app/jobs/decidim/proposals/hide_all_created_by_author_job.rb index 521fbf8897c08..f197e9fbfa23b 100644 --- a/decidim-proposals/app/jobs/decidim/proposals/hide_all_created_by_author_job.rb +++ b/decidim-proposals/app/jobs/decidim/proposals/hide_all_created_by_author_job.rb @@ -11,9 +11,6 @@ def perform(resource:, extra: {}) Decidim::Proposals::Proposal.not_hidden.from_author(resource).find_each do |content| hide_content(content, extra[:event_author], extra[:justification]) end - Decidim::Proposals::CollaborativeDraft.not_hidden.from_author(resource).find_each do |content| - hide_content(content, extra[:event_author], extra[:justification]) - end end end end diff --git a/decidim-proposals/app/models/decidim/proposals/collaborative_draft.rb b/decidim-proposals/app/models/decidim/proposals/collaborative_draft.rb deleted file mode 100644 index c045b23f57958..0000000000000 --- a/decidim-proposals/app/models/decidim/proposals/collaborative_draft.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraft < Proposals::ApplicationRecord - include Decidim::Resourceable - include Decidim::Coauthorable - include Decidim::Taxonomizable - include Decidim::HasComponent - include Decidim::ScopableResource - include Decidim::HasReference - include Decidim::HasCategory - include Decidim::Reportable - include Decidim::HasAttachments - include Decidim::Followable - include Decidim::Proposals::CommentableCollaborativeDraft - include Decidim::Traceable - include Decidim::Loggable - include Decidim::Randomable - include Decidim::FilterableResource - - has_many :collaborator_requests, - class_name: "Decidim::Proposals::CollaborativeDraftCollaboratorRequest", - foreign_key: :decidim_proposals_collaborative_draft_id, - dependent: :destroy - - has_many :requesters, - through: :collaborator_requests, - source: :user, - class_name: "Decidim::User", - foreign_key: :decidim_user_id - - geocoded_by :address - - STATES = { open: 0, published: 10, withdrawn: -1 }.freeze - - enum :state, STATES, default: "open" - scope :except_withdrawn, -> { not_withdrawn.or(where(state: nil)) } - - scope_search_multi :with_any_state, [:open, :published, :withdrawn] - - # Checks whether the user can edit the given proposal. - # - # user - the user to check for authorship - def editable_by?(user) - authored_by?(user) - end - - def presenter - Decidim::Proposals::CollaborativeDraftPresenter.new(self) - end - - # Public: Overrides the `reported_attributes` Reportable concern method. - def reported_attributes - [:body] - end - - # Public: Overrides the `reported_searchable_content_extras` Reportable concern method. - def reported_searchable_content_extras - [authors.map(&:name).join("\n")] - end - - # Create the :search_text ransacker alias for searching from both :title or :body. - ransacker_text_multi :search_text, [:title, :body] - - def self.ransackable_scopes(_auth_object = nil) - [:with_any_state, :related_to, :with_any_taxonomies] - end - - def self.ransackable_attributes(_auth_object = nil) - %w(id_string search_text title body) - end - - def self.ransackable_associations(_auth_object = nil) - %w(taxonomies) - end - end - end -end diff --git a/decidim-proposals/app/models/decidim/proposals/collaborative_draft_collaborator_request.rb b/decidim-proposals/app/models/decidim/proposals/collaborative_draft_collaborator_request.rb deleted file mode 100644 index 972f08b3e661c..0000000000000 --- a/decidim-proposals/app/models/decidim/proposals/collaborative_draft_collaborator_request.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # A collaborative_draft can accept requests to coauthor and contribute - class CollaborativeDraftCollaboratorRequest < Proposals::ApplicationRecord - belongs_to :collaborative_draft, class_name: "Decidim::Proposals::CollaborativeDraft", foreign_key: :decidim_proposals_collaborative_draft_id - belongs_to :user, class_name: "Decidim::User", foreign_key: :decidim_user_id - end - end -end diff --git a/decidim-proposals/app/models/decidim/proposals/proposal.rb b/decidim-proposals/app/models/decidim/proposals/proposal.rb index c9c1404723cc8..2048ef5d29efe 100644 --- a/decidim-proposals/app/models/decidim/proposals/proposal.rb +++ b/decidim-proposals/app/models/decidim/proposals/proposal.rb @@ -174,6 +174,26 @@ def self.with_more_authors_available?(component) .exists? end + def self.most_commented_available?(component) + return false unless component.settings.comments_enabled? + + where(component:) + .published + .not_hidden + .not_withdrawn + .where("comments_count > 0") + .exists? + end + + def self.most_liked_available?(component) + where(component:) + .published + .not_hidden + .not_withdrawn + .where("likes_count > 0") + .exists? + end + acts_as_list scope: :decidim_component_id searchable_fields({ @@ -387,13 +407,13 @@ def self.ransack(params = {}, options = {}) # method to filter by assigned evaluator role ID def self.evaluator_role_ids_has(value) - query = <<-SQL.squish - :value = any( - (SELECT decidim_proposals_evaluation_assignments.evaluator_role_id - FROM decidim_proposals_evaluation_assignments - WHERE decidim_proposals_evaluation_assignments.decidim_proposal_id = decidim_proposals_proposals.id + query = <<~SQL.squish + :value = any( + (SELECT decidim_proposals_evaluation_assignments.evaluator_role_id + FROM decidim_proposals_evaluation_assignments + WHERE decidim_proposals_evaluation_assignments.decidim_proposal_id = decidim_proposals_proposals.id + ) ) - ) SQL where(query, value:) end @@ -446,14 +466,14 @@ def self.sort_by_translated_title_desc end ransacker :is_emendation do |_parent| - query = <<-SQL.squish - ( - SELECT EXISTS ( - SELECT 1 FROM decidim_amendments - WHERE decidim_amendments.decidim_emendation_type = 'Decidim::Proposals::Proposal' - AND decidim_amendments.decidim_emendation_id = decidim_proposals_proposals.id + query = <<~SQL.squish + ( + SELECT EXISTS ( + SELECT 1 FROM decidim_amendments + WHERE decidim_amendments.decidim_emendation_type = 'Decidim::Proposals::Proposal' + AND decidim_amendments.decidim_emendation_id = decidim_proposals_proposals.id + ) ) - ) SQL Arel.sql(query) end diff --git a/decidim-proposals/app/packs/entrypoints/decidim_proposals_admin.js b/decidim-proposals/app/packs/entrypoints/decidim_proposals_admin.js index 9f1d6fe542638..63795b3bd729e 100644 --- a/decidim-proposals/app/packs/entrypoints/decidim_proposals_admin.js +++ b/decidim-proposals/app/packs/entrypoints/decidim_proposals_admin.js @@ -1,3 +1,4 @@ import "src/decidim/proposals/admin/proposals" import "src/decidim/proposals/admin/proposals_form" import "src/decidim/proposals/admin/proposals_merge" +import "src/decidim/proposals/admin/import_proposals" diff --git a/decidim-proposals/app/packs/src/decidim/proposals/admin/controllers/import_proposals/controller.js b/decidim-proposals/app/packs/src/decidim/proposals/admin/controllers/import_proposals/controller.js new file mode 100644 index 0000000000000..54c4d50e3514d --- /dev/null +++ b/decidim-proposals/app/packs/src/decidim/proposals/admin/controllers/import_proposals/controller.js @@ -0,0 +1,110 @@ +import { Controller } from "@hotwired/stimulus" + +/** + * Stimulus controller for the admin import-proposals form. + * + * Watches a `` element used to choose the origin component. + * - `container` – The wrapper element where the state checkboxes are rendered. + * + * Values: + * - `statesUrl` {String} – Base URL of the endpoint that returns available states. + * - `selectedStates` {Array} – Pre-selected state tokens (populated on page load + * when re-rendering a previously submitted form). + */ +export default class ImportProposalsController extends Controller { + + /** + * Lifecycle callback invoked by Stimulus when the controller is connected to + * the DOM. Triggers an initial state fetch based on the currently selected + * component so that a pre-filled form displays the correct checkboxes. + * @returns {void} + */ + connect() { + this._fetchStates(this.selectTarget.value); + } + + /** + * Triggered when the select value changes. + * @param {Event} event - The change event fired by the select element. + * @returns {void} + */ + onSelectChange(event) { + this._fetchStates(event.target.value); + } + + /** + * Escapes a string for safe insertion into HTML. + * @param {string} str - The string to escape. + * @returns {string} The escaped HTML string. + */ + _escapeHtml(str) { + const div = document.createElement("div"); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; + } + + /** + * Fetches the available states for the given component ID and renders them. + * @param {string} componentId - The ID of the selected component to fetch states for. + * @returns {void} + */ + _fetchStates(componentId) { + const container = this.containerTarget; + if (!componentId) { + container.innerHTML = ""; + container.style.display = "none"; + return; + } + + const url = `${this.statesUrlValue}?origin_id=${componentId}`; + fetch(url, { + credentials: "same-origin", + headers: { Accept: "application/json" } + }).then((res) => { + return res.json(); + }).then((states) => { + if (!states.length) { + container.innerHTML = ""; + container.style.display = "none"; + return; + } + + const selectedStates = this.selectedStatesValue; + const wrapper = document.createElement("div"); + wrapper.className = "row column"; + + states.forEach((state) => { + const div = document.createElement("div"); + const label = document.createElement("label"); + const input = document.createElement("input"); + input.type = "checkbox"; + input.name = "proposals_import[states][]"; + input.value = state.token; + input.checked = selectedStates.includes(state.token); + label.appendChild(input); + label.appendChild(document.createTextNode(` ${state.title}`)); + div.appendChild(label); + wrapper.appendChild(div); + }); + + container.innerHTML = ""; + container.appendChild(wrapper); + container.style.display = "block"; + }).catch(() => { + container.innerHTML = ""; + container.style.display = "none"; + }); + } +} + +ImportProposalsController.targets = ["select", "container"] +ImportProposalsController.values = { + statesUrl: String, + selectedStates: { type: Array, default: [] } +} diff --git a/decidim-proposals/app/packs/src/decidim/proposals/admin/import_proposals.js b/decidim-proposals/app/packs/src/decidim/proposals/admin/import_proposals.js new file mode 100644 index 0000000000000..090a726a0fdb0 --- /dev/null +++ b/decidim-proposals/app/packs/src/decidim/proposals/admin/import_proposals.js @@ -0,0 +1,5 @@ +import { Application } from "@hotwired/stimulus" +import ImportProposalsController from "src/decidim/proposals/admin/controllers/import_proposals/controller.js" + +const application = Application.start() +application.register("import-proposals", ImportProposalsController) diff --git a/decidim-proposals/app/permissions/decidim/proposals/permissions.rb b/decidim-proposals/app/permissions/decidim/proposals/permissions.rb index 91b13ef2ec6b5..6a01c04321eea 100644 --- a/decidim-proposals/app/permissions/decidim/proposals/permissions.rb +++ b/decidim-proposals/app/permissions/decidim/proposals/permissions.rb @@ -14,8 +14,6 @@ def permissions case permission_action.subject when :proposal apply_proposal_permissions(permission_action) unless permission_action.action == :read - when :collaborative_draft - apply_collaborative_draft_permissions(permission_action) when :proposal_coauthor_invites apply_proposal_coauthor_invites(permission_action) else @@ -107,61 +105,6 @@ def can_unvote_proposal? toggle_allow(is_allowed) end - def apply_collaborative_draft_permissions(permission_action) - case permission_action.action - when :create - can_create_collaborative_draft? - when :edit - can_edit_collaborative_draft? - when :publish - can_publish_collaborative_draft? - when :request_access - can_request_access_collaborative_draft? - when :react_to_request_access - can_react_to_request_access_collaborative_draft? - end - end - - def collaborative_draft - @collaborative_draft ||= context.fetch(:collaborative_draft, nil) - end - - def collaborative_drafts_enabled? - component_settings.collaborative_drafts_enabled - end - - def can_create_collaborative_draft? - return toggle_allow(false) unless collaborative_drafts_enabled? - - toggle_allow(current_settings&.creation_enabled? && authorized?(:create)) - end - - def can_edit_collaborative_draft? - return toggle_allow(false) unless collaborative_drafts_enabled? && collaborative_draft.open? - - toggle_allow(collaborative_draft.editable_by?(user)) - end - - def can_publish_collaborative_draft? - return toggle_allow(false) unless collaborative_drafts_enabled? && collaborative_draft.open? - - toggle_allow(collaborative_draft.created_by?(user)) - end - - def can_request_access_collaborative_draft? - return toggle_allow(false) unless collaborative_drafts_enabled? && collaborative_draft.open? - return toggle_allow(false) if collaborative_draft.requesters.include?(user) - - toggle_allow(!collaborative_draft.editable_by?(user)) - end - - def can_react_to_request_access_collaborative_draft? - return toggle_allow(false) unless collaborative_drafts_enabled? && collaborative_draft.open? - return toggle_allow(false) if collaborative_draft.requesters.include? user - - toggle_allow(collaborative_draft.created_by?(user)) - end - def apply_proposal_coauthor_invites(permission_action) return toggle_allow(false) unless coauthor return toggle_allow(false) unless proposal diff --git a/decidim-proposals/app/presenters/decidim/proposals/collaborative_draft_presenter.rb b/decidim-proposals/app/presenters/decidim/proposals/collaborative_draft_presenter.rb deleted file mode 100644 index eefa848dde936..0000000000000 --- a/decidim-proposals/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # - # Decorator for collaborative drafts - # - class CollaborativeDraftPresenter < ProposalPresenter - def author - @author ||= Decidim::UserPresenter.new(__getobj__.coauthorships.first.author) - end - - alias collaborative_draft proposal - - def collaborative_draft_path - Decidim::ResourceLocatorPresenter.new(collaborative_draft).path - end - end - end -end diff --git a/decidim-proposals/app/services/decidim/proposals/collaborative_draft_diff_renderer.rb b/decidim-proposals/app/services/decidim/proposals/collaborative_draft_diff_renderer.rb deleted file mode 100644 index 3994e4e02775d..0000000000000 --- a/decidim-proposals/app/services/decidim/proposals/collaborative_draft_diff_renderer.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - class CollaborativeDraftDiffRenderer < DiffRenderer - private - - def attribute_types - { - title: :string, - body: :string, - decidim_category_id: :category, - decidim_scope_id: :scope, - address: :string, - latitude: :string, - longitude: :string, - decidim_proposals_proposal_state_id: :string - } - end - end - end -end diff --git a/decidim-proposals/app/views/decidim/proposals/admin/proposals/index.html.erb b/decidim-proposals/app/views/decidim/proposals/admin/proposals/index.html.erb index ba74903ccca8c..e16c524e295ca 100644 --- a/decidim-proposals/app/views/decidim/proposals/admin/proposals/index.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/admin/proposals/index.html.erb @@ -23,10 +23,6 @@
<%= admin_filter_selector(filter_prefix_key) %> - <% if component_settings.collaborative_drafts_enabled? %> -
<%= t("deprecation_warning_collaborative_drafts_html", scope: "decidim.proposals.admin") %>
- <% end %> -
<%= render partial: "proposals-thead" %> diff --git a/decidim-proposals/app/views/decidim/proposals/admin/proposals/show.html.erb b/decidim-proposals/app/views/decidim/proposals/admin/proposals/show.html.erb index 7cf1f1e88b167..5ef721b85bd3b 100644 --- a/decidim-proposals/app/views/decidim/proposals/admin/proposals/show.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/admin/proposals/show.html.erb @@ -1,4 +1,6 @@ +<% add_decidim_page_title(t(".title")) %> <% add_decidim_page_title(translated_attribute(proposal.title)) %> +
<%= render partial: "decidim/admin/shared/adjacent_navigation", locals: { adjacent_paths: filtered_adjacent_paths(proposal, :proposal_path) } %> diff --git a/decidim-proposals/app/views/decidim/proposals/admin/proposals_imports/new.html.erb b/decidim-proposals/app/views/decidim/proposals/admin/proposals_imports/new.html.erb index e49e717c12224..0ae32990cf8ce 100644 --- a/decidim-proposals/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/admin/proposals_imports/new.html.erb @@ -1,4 +1,5 @@ <% add_decidim_page_title(t(".title")) %> +<%= append_javascript_pack_tag "decidim_proposals_admin" %>

<%= t(".title") %> @@ -7,25 +8,21 @@
- <%= decidim_form_for(@form, url: proposals_import_path, html: { class: "form form-defaults import_proposals" }) do |f| %> + <%= decidim_form_for(@form, url: proposals_import_path, local: true, html: { class: "form form-defaults import_proposals" }) do |f| %> <% if @form.origin_components.any? %>
-
+
- <%= f.select :origin_component_id, @form.origin_components_collection, prompt: t(".select_component") %> + <%= f.select :origin_component_id, @form.origin_components_collection, { prompt: t(".select_component") }, { data: { import_proposals_target: "select", action: "change->import-proposals#onSelectChange" } } %>
- <% if @form.available_states.any? %> -
- <%= f.collection_check_boxes :states, @form.available_states, :token, ->(a) { translated_attribute(a.title) } do |builder| %> -
- <%= builder.label { builder.check_box + builder.text } %> -
- <% end %> -
- <% end %> +
<%= f.check_box :keep_authors %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_accept_request_access_form.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_accept_request_access_form.html.erb deleted file mode 100644 index 3335c4eadfead..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_accept_request_access_form.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -<% if allowed_to?(:react_to_request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> - <%= decidim_form_for(@accept_request_form, url: request_accept_collaborative_draft_path(@collaborative_draft)) do |form| %> - <%= form.hidden_field :id, value: @collaborative_draft.id %> - <%= form.hidden_field :state, value: @collaborative_draft.state %> - <%= form.hidden_field :requester_user_id, value: requester.id %> - <%= form.submit accept_request_button_label, class: "button button__sm button__secondary w-full", data: { disable: true } %> - <% end %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb deleted file mode 100644 index cc80324fd309b..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb +++ /dev/null @@ -1,9 +0,0 @@ - -<% if allowed_to?(:edit, :collaborative_draft, collaborative_draft: @collaborative_draft) %> - -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_draft_aside.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_draft_aside.html.erb deleted file mode 100644 index 349feab7b7286..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_draft_aside.html.erb +++ /dev/null @@ -1,38 +0,0 @@ -
- <% if @collaborative_draft.published? %> - <%= cell "decidim/proposals/collaborative_draft_link_to_proposal", @collaborative_draft %> - <% else %> -
- <%= resource_version_number(@collaborative_draft.versions_count, "h4") %> - <%= resource_version_of(@collaborative_draft.versions_count) %> - <%= link_to_other_resource_versions(collaborative_draft_version_path(@collaborative_draft, @collaborative_draft.versions.count)) %> -
- <% end %> -
- -<% if allowed_to?(:publish, :collaborative_draft, collaborative_draft: @collaborative_draft) || @collaborative_draft.requesters.include?(current_user) || allowed_to?(:request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> -
- <% if allowed_to?(:publish, :collaborative_draft, collaborative_draft: @collaborative_draft) %> -
- <%= cell "decidim/proposals/irreversible_action_modal", @collaborative_draft, action: :publish %> - -
- <%= t("publish_info", scope:"decidim.proposals.collaborative_drafts.show") %> - <%= cell "decidim/proposals/irreversible_action_modal", @collaborative_draft, action: :withdraw %> -
-
- <% end %> - - <%= render "request_access_form" %> - - <% if @collaborative_draft.requesters.include? current_user %> - - <% end %> -
-<% end %> - -
- <%= render partial: "collaborator_requests" %> -
diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_drafts.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_drafts.html.erb deleted file mode 100644 index d8c150d6c6cec..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborative_drafts.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% if @collaborative_drafts.empty? %> - <%= cell("decidim/announcement", params[:filter].present? ? t("empty_filters", scope: "decidim.proposals.collaborative_drafts") : t("empty", scope: "decidim.proposals.collaborative_drafts")) %> -<% else %> -

<%= t("count", scope: "decidim.proposals.collaborative_drafts.index", count: @collaborative_drafts.length) %>

- - <%= order_selector available_orders, i18n_scope: "decidim.proposals.collaborative_drafts.orders" %> - -
- <% @collaborative_drafts.each do |draft| %> - <%= card_for draft %> - <% end %> -
- - <%= decidim_paginate @collaborative_drafts %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborator_requests.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborator_requests.html.erb deleted file mode 100644 index fb001f312f988..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_collaborator_requests.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -<% if @collaborative_draft.requesters.presence && allowed_to?(:react_to_request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> -
-

<%= t("title", scope: "decidim.proposals.collaborative_drafts.requests.collaboration_requests") %>

- - <% @collaborative_draft.requesters.each do |requester| %> -
- <%= cell "decidim/author", present(requester) %> - -
- <%= render partial: "accept_request_access_form", locals: { requester: } %> - <%= render partial: "reject_request_access_form", locals: { requester: } %> -
-
- <% end %> -
-<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb deleted file mode 100644 index ecb6049f3bbd6..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +++ /dev/null @@ -1,26 +0,0 @@ -<%= form_required_explanation %> - -<%= form.text_field :title, value: form_presenter.title, data: { controller: "character-counter" } %> -<%= text_editor_for_proposal_body(form) %> - -<% if @form.geocoding_enabled? %> - <%= form.geocoding_field :address %> -<% end %> - -<% if @form.taxonomy_filters&.any? %> - <% @form.taxonomy_filters.each do |filter| %> - <%= filter_taxonomy_items_select_field form, :taxonomies, filter %> - <% end %> -<% end %> - -<% if component_settings.attachments_allowed? %> - <%= form.attachment :documents, - multiple: false, - label: t("decidim.proposals.collaborative_drafts.new.add_file"), - button_label: t("decidim.proposals.collaborative_drafts.new.add_file"), - button_edit_label: t("decidim.proposals.collaborative_drafts.new.edit_file"), - button_class: "button button__lg button__transparent-secondary w-full", - help_text: t("attachment_legend", scope: "decidim.proposals.collaborative_drafts.edit"), - help_i18n_scope: "decidim.forms.file_help.file", - paragraph: true %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_reject_request_access_form.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_reject_request_access_form.html.erb deleted file mode 100644 index 230b80e55f585..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_reject_request_access_form.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -<% if allowed_to?(:react_to_request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> - <%= decidim_form_for(@reject_request_form, url: request_reject_collaborative_draft_path(@collaborative_draft)) do |form| %> - <%= form.hidden_field :id, value: @collaborative_draft.id %> - <%= form.hidden_field :state, value: @collaborative_draft.state %> - <%= form.hidden_field :requester_user_id, value: requester.id %> - <%= form.submit reject_request_button_label, class: "button button__sm button__transparent-secondary w-full", data: { disable: true } %> - <% end %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_request_access_form.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_request_access_form.html.erb deleted file mode 100644 index 05ca1ba1596e9..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/_request_access_form.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -<% if allowed_to?(:request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> - <%= decidim_form_for(@request_access_form, url: request_access_collaborative_draft_path(@collaborative_draft)) do |form| %> - <%= form.hidden_field :id, value: @collaborative_draft.id %> - <%= form.hidden_field :state, value: @collaborative_draft.state %> - <%= form.submit t(:request_access, scope: "decidim.proposals.collaborative_drafts.show"), class: "button button__lg button__secondary w-full", data: { disable: true } %> - <% end %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/edit.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/edit.html.erb deleted file mode 100644 index 12456fdf8c796..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/edit.html.erb +++ /dev/null @@ -1,31 +0,0 @@ -<% add_decidim_page_title(proposal_wizard_step_title(action_name)) %> - -<%= append_stylesheet_pack_tag "decidim_proposals", media: "all" %> -<%= append_javascript_pack_tag "decidim_proposals" %> - -<%= render layout: "layouts/decidim/shared/layout_center" do %> -
-

- <%= t("title", scope: "decidim.proposals.collaborative_drafts.edit") %> -

-
- - <% if translated_attribute(component_settings.new_proposal_help_text).present? %> - <%= cell("decidim/announcement", component_settings.new_proposal_help_text) %> - <% end %> - - <%= decidim_form_for(@form) do |form| %> -
- <%= render partial: "edit_form_fields", locals: { form: } %> -
- -
- <%= link_to :back, class: "button button__sm md:button__lg button__text-secondary" do %> - <%= icon "arrow-left-line" %> - <%= t("back", scope: "decidim.proposals.collaborative_drafts.edit") %> - <% end %> - - <%= form.submit t("send", scope: "decidim.proposals.collaborative_drafts.edit"), class: "button button__sm md:button__lg button__secondary", data: { disable: true } %> -
- <% end %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.html.erb deleted file mode 100644 index 8d6d8aba02770..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.html.erb +++ /dev/null @@ -1,35 +0,0 @@ -<% add_decidim_meta_tags( - description: translated_attribute(current_participatory_space.short_description), - title: component_name, - url: proposals_url, - resource: current_component) %> - -<%= append_stylesheet_pack_tag "decidim_proposals", media: "all" %> -<%= append_javascript_pack_tag "decidim_proposals" %> - -<% content_for :aside do %> - -

<%= component_name %>

- - <% if current_settings.creation_enabled %> - <%= action_authorized_link_to :create, new_collaborative_draft_path, permissions_holder: current_component, class: "button button__sm button__transparent-secondary", data: { "redirect_url" => new_collaborative_draft_path } do %> - <%= t("new_collaborative_draft", scope: "decidim.proposals.collaborative_drafts.new_collaborative_draft_button") %> - <%= icon "add-line" %> - <% end %> - <% end %> - - <%= render layout: "decidim/shared/filters", locals: { filter_sections: collaborative_drafts_filter_sections, search_variable: :search_text_cont, skip_to_id: "collaborative_drafts" } do %> - <%= hidden_field_tag :order, order, id: nil, class: "order_filter" %> - <% end %> - -<% end %> - -<%= render layout: "layouts/decidim/shared/layout_two_col" do %> - - <%= render partial: "decidim/shared/component_announcement" %> - -
- <%= render partial: "collaborative_drafts" %> -
- -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.js.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.js.erb deleted file mode 100644 index 0b1fb43b0a96b..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/index.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -var $collaborative_drafts = $('#collaborative_drafts'); -var $orderFilterInput = $('.order_filter'); - -$collaborative_drafts.html('<%= j(render partial: "collaborative_drafts").strip.html_safe %>'); -$orderFilterInput.val('<%= order %>'); diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/new.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/new.html.erb deleted file mode 100644 index 53c610d77af9d..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/new.html.erb +++ /dev/null @@ -1,30 +0,0 @@ -<% add_decidim_page_title(t("decidim.proposals.collaborative_drafts.wizard_header.title")) %> - -<%= append_stylesheet_pack_tag "decidim_proposals", media: "all" %> -<%= append_javascript_pack_tag "decidim_proposals" %> - -<%= render layout: "layouts/decidim/shared/layout_center" do %> -
-

- <%= t("title", scope: "decidim.proposals.collaborative_drafts.wizard_header") %> -

-
- - <% if translated_attribute(component_settings.new_proposal_help_text).present? %> - <%= cell("decidim/announcement", component_settings.new_proposal_help_text) %> - <% end %> - - <%= decidim_form_for(@form) do |form| %> -
- <%= render partial: "edit_form_fields", locals: { form: } %> -
- -
- <%= link_to collaborative_drafts_path, class: "button button__sm md:button__lg button__text-secondary" do %> - <%= icon "arrow-left-line" %> - <%= t("back_from_collaborative_draft", scope: "decidim.proposals.collaborative_drafts.wizard_aside").html_safe %> - <% end %> - <%= form.submit t("send", scope: "decidim.proposals.collaborative_drafts.new"), class: "button button__sm md:button__lg button__secondary", data: { disable: true } %> -
- <% end %> -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/show.html.erb b/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/show.html.erb deleted file mode 100644 index 5a20c5bc9d4a2..0000000000000 --- a/decidim-proposals/app/views/decidim/proposals/collaborative_drafts/show.html.erb +++ /dev/null @@ -1,74 +0,0 @@ -<% add_decidim_page_title(t("name", scope: "decidim.proposals.collaborative_drafts")) %> -<% add_decidim_meta_tags( - description: present(@collaborative_draft).body, - title: present(@collaborative_draft).title, - url: collaborative_draft_url(@collaborative_draft.id), - resource: @collaborative_draft) %> - -<%= append_stylesheet_pack_tag "decidim_proposals", media: "all" %> -<%= append_javascript_pack_tag "decidim_proposals" %> - -<% content_for :aside do %> - <%= render partial: "collaborative_draft_aside" %> -<% end %> - -<%= render layout: "layouts/decidim/shared/layout_item", locals: { back_path: collaborative_drafts_path } do %> - -
- <%= cell("decidim/announcement", t("info-message", scope: "decidim.proposals.collaborative_drafts.show").html_safe) if current_user.nil? || allowed_to?(:request_access, :collaborative_draft, collaborative_draft: @collaborative_draft) %> - -

<%= present(@collaborative_draft).title(html_escape: true) %>

- - <% if component_settings.geocoding_enabled? %> -
- <%= render partial: "decidim/shared/static_map", locals: { icon_name: "proposals", geolocalizable: @collaborative_draft } %> -
- <% end %> - - <% if @collaborative_draft.state %> -
- - <%= humanize_collaborative_draft_state(@collaborative_draft.state) %> - -
- <% end %> - -
"> -
-
- <%= cell "decidim/coauthorships", @collaborative_draft, context_actions: [] %> -
- <%= render "decidim/shared/resource_actions", resource: @collaborative_draft do %> - <%= render "decidim/proposals/collaborative_drafts/collaborative_actions" %> - <% end %> -
-
-
- -
-
- <%= decidim_sanitize_editor present(@collaborative_draft).body(links: true) %> -
-
- - <%= attachments_for @collaborative_draft %> - - <%= cell "decidim/tags", @collaborative_draft %> - -
- <%= cell "decidim/comments_button", nil %> -
- <%= cell "decidim/share_widget", @collaborative_draft %> -
-
- - <% content_for :item_footer do %> - <%= comments_for @collaborative_draft %> - - - <% end %> - -<% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/proposals/_proposal_aside.html.erb b/decidim-proposals/app/views/decidim/proposals/proposals/_proposal_aside.html.erb index 93bfc2b63b011..04a5ffd3b106c 100644 --- a/decidim-proposals/app/views/decidim/proposals/proposals/_proposal_aside.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/proposals/_proposal_aside.html.erb @@ -14,6 +14,5 @@ <% end %>
- <%= cell "decidim/proposals/proposal_link_to_collaborative_draft", @proposal %> <%= cell "decidim/proposals/proposal_link_to_rejected_emendation", @proposal %>
diff --git a/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb b/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb index aa0cce1621f7f..ff8eccc70113c 100644 --- a/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb @@ -20,13 +20,6 @@ <%= icon "add-line" %> <% end %> <% end %> - - <% if component_settings.collaborative_drafts_enabled? %> - <%= link_to collaborative_drafts_path, class: "button button__sm button__transparent-secondary" do %> - <%= t("collaborative_drafts_list", scope: "decidim.proposals.proposals.index") %> - <%= icon "edit-2-line" %> - <% end %> - <% end %>
<%= render layout: "decidim/shared/filters", locals: { filter_sections: , search_variable: :search_text_cont, skip_to_id: "proposals" } do %> diff --git a/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb b/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb index 5755671bc00bd..c5115880abcaa 100644 --- a/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb @@ -114,32 +114,9 @@ extra_admin_link( <%= comments_for @proposal %> - <%= decidim_modal id: fingerprint_id, class: "fingerprint-modal" do %> -
- <%= icon "fingerprint-line" %> -

<%= t "decidim.fingerprint.title" %>

-
-

<%= t "decidim.fingerprint.explanation" %>

-
- <%= t "decidim.fingerprint.value" %>: - <%= decidim_html_escape @proposal.fingerprint.value %> -
-
- <%= t "decidim.fingerprint.source" %>: - <%= @proposal.fingerprint.source %> -
-

<%= t("decidim.fingerprint.replicate_help", online_calculator_link: link_to(t("decidim.fingerprint.online_calculator_name"), "http://www.md5calc.com/sha256", target: "_blank", rel: "noopener")).html_safe %>

-
-
- <% end %> <% end %> <% end %> diff --git a/decidim-proposals/app/views/decidim/proposals/versions/show.html.erb b/decidim-proposals/app/views/decidim/proposals/versions/show.html.erb index 26ebbbb3b8a20..16d38f3a2c9d9 100644 --- a/decidim-proposals/app/views/decidim/proposals/versions/show.html.erb +++ b/decidim-proposals/app/views/decidim/proposals/versions/show.html.erb @@ -1,10 +1,5 @@ <% add_decidim_page_title(t("changes_at_title", scope: "decidim.version.show", title: versioned_resource.title)) %> <% add_decidim_page_title(t("decidim.proposals.versions.index.title")) %> -<% -if versioned_resource.is_a?(Decidim::Proposals::CollaborativeDraft) - add_decidim_page_title(Decidim::Proposals::CollaborativeDraft.model_name.human(count: 2)) -end -%> <% content_for :aside do %> <%= cell( diff --git a/decidim-proposals/config/locales/en.yml b/decidim-proposals/config/locales/en.yml index 2fb6fe9c1b0a3..5dc98243f4b0f 100644 --- a/decidim-proposals/config/locales/en.yml +++ b/decidim-proposals/config/locales/en.yml @@ -499,7 +499,6 @@ en: deleted_proposals_info: Deleted proposals can be restored from the trash. preview: Preview view_deleted_proposals: View deleted proposals - deprecation_warning_collaborative_drafts_html: "⚠️ Deprecation Notice. The Collaborative Drafts feature will be removed in Decidim v0.32. Organizations using it can switch to the new proposal co-authorship feature." evaluation_assignments: create: invalid: There was a problem assigning proposals to a evaluator. @@ -682,6 +681,7 @@ en: related_meetings: Related meetings remove_assignment: Remove assignment remove_assignment_confirmation: Are you sure you want to remove the evaluator from this proposal? + title: Answer proposal votes_count: Votes count update_taxonomies: invalid: 'These proposals already had the %{taxonomies} taxonomies: %{proposals}.' @@ -743,103 +743,6 @@ en: all: All amendments: Amendments proposals: Proposals - collaborative_drafts: - collaborative_draft: - publish: - error: There was a problem publishing the collaborative draft. - irreversible_action_modal: - body: After publishing the draft as a proposal, it will not be editable anymore. The proposal will not accept new authors or contributions. - cancel: Cancel - ok: Publish as a Proposal - title: The following action is irreversible - success: Collaborative draft published successfully as a proposal. - withdraw: - error: There was a problem closing the collaborative draft. - irreversible_action_modal: - body: After closing the draft, it will not be editable anymore. The draft will not accept new authors or contributions. - cancel: Cancel - ok: Withdraw the collaborative draft - title: The following action is irreversible - success: Collaborative draft withdrawn successfully. - create: - error: There was a problem creating this collaborative draft. - success: Collaborative draft successfully created. - edit: - attachment_legend: Add a document or an image - back: Back - send: Send - title: Edit collaborative draft - empty: There are no collaborative drafts yet - empty_filters: There is no collaborative draft with this criteria - filters: - all: All - amendment: Amendments - open: Open - published: Published - related_to: Related to - search: Search - state: Status - withdrawn: Withdrawn - filters_small_view: - close_modal: Close modal - filter: Filter - filter_by: Filter by - unfold: Unfold - index: - count: - one: "%{count} collaborative draft" - other: "%{count} collaborative drafts" - name: Collaborative drafts - new: - add_file: Add file - edit_file: Edit file - send: Continue - new_collaborative_draft_button: - new_collaborative_draft: New collaborative draft - orders: - label: 'Order drafts by:' - most_contributed: Most contributed - random: Random - recent: Recent - requests: - accepted_request: - error: Could not be accepted as a collaborator, please try again later. - success: "@%{user} has been accepted as a collaborator successfully." - access_requested: - error: Your request could not be completed, please try again later. - success: Your request to collaborate has been successfully sent. - collaboration_requests: - accept_request: Accept - reject_request: Reject - title: Collaboration requests - rejected_request: - error: Could not be rejected as a collaborator, please try again later. - success: "@%{user} has been successfully rejected as a collaborator." - show: - edit: Edit - final_proposal: Final proposal - final_proposal_help_text: This draft is finished. Check out the final proposal - hidden_authors_count: - one: and %{count} more person - other: and %{count} more people - info-message: This is a collaborative draft for a proposal. This means that you can help their authors to shape the proposal using the comment section below or improve it directly by requesting access to edit it. Once the authors grant you access, you will be able to make changes to this draft. - publish: Publish - publish_info: Publish this version of the draft or - published_proposal: Published proposal - request_access: Request access - requested_access: Access requested - withdraw: withdraw the draft - states: - open: Open - published: Published - withdrawn: Withdrawn - update: - error: There was a problem saving the collaborative draft. - success: Collaborative draft successfully updated. - wizard_aside: - back_from_collaborative_draft: Back to collaborative drafts - wizard_header: - title: Create your collaborative draft content_blocks: highlighted_proposals: name: Proposals @@ -941,7 +844,6 @@ en: voted: Voted index: click_here: See all proposals - collaborative_drafts_list: Access collaborative drafts count: one: "%{count} proposal" other: "%{count} proposals" @@ -988,8 +890,6 @@ en: hidden_likes_count: one: and %{count} more person other: and %{count} more people - link_to_collaborative_draft_help_text: This proposal is the result of a collaborative draft. Review the history - link_to_collaborative_draft_text: See the collaborative draft link_to_promoted_emendation_help_text: This proposal is a promoted emendation link_to_promoted_emendation_text: See the rejected emendation. link_to_proposal_from_emendation_help_text: This is a rejected emendation diff --git a/decidim-proposals/db/data/20260224210316_remove_collaborative_drafts_references.rb b/decidim-proposals/db/data/20260224210316_remove_collaborative_drafts_references.rb new file mode 100644 index 0000000000000..f3c4a620eeca1 --- /dev/null +++ b/decidim-proposals/db/data/20260224210316_remove_collaborative_drafts_references.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +class RemoveCollaborativeDraftsReferences < ActiveRecord::Migration[7.2] + class CollaborativeDraft < ApplicationRecord + self.table_name = "decidim_proposals_collaborative_drafts" + end + + class CollaborativeDraftCollaboratorRequest < ApplicationRecord + self.table_name = "decidim_proposals_collaborative_draft_collaborator_requests" + end + + class Notification < ApplicationRecord + self.table_name = "decidim_notifications" + end + + class Follow < ApplicationRecord + self.table_name = "decidim_follows" + end + + class Moderation < ApplicationRecord + self.table_name = "decidim_moderations" + end + + class Coauthorship < ApplicationRecord + self.table_name = "decidim_coauthorships" + end + + class ActionLog < ApplicationRecord + self.table_name = "decidim_action_logs" + end + + class Comment < ApplicationRecord + self.table_name = "decidim_comments_comments" + end + + class ResourceLink < ApplicationRecord + self.table_name = "decidim_resource_links" + end + + class Categorization < ApplicationRecord + self.table_name = "decidim_categorizations" + end + + class Attachment < ApplicationRecord + self.table_name = "decidim_attachments" + end + + class Version < ApplicationRecord + self.table_name = "versions" + end + + COLLABORATIVE_DRAFT_TYPE = "Decidim::Proposals::CollaborativeDraft" + COLLABORATIVE_DRAFT_COLLABORATOR_REQUEST_TYPE = "Decidim::Proposals::CollaborativeDraftCollaboratorRequest" + + def up + delete_notifications + delete_follows + delete_reports + delete_coauthorships + delete_action_logs + delete_comments + delete_resource_links + delete_categorizations + delete_attachments + delete_paper_trail_versions_for_collaborative_drafts + delete_paper_trail_versions_for_collaborator_requests + end + + def down + raise ActiveRecord::IrreversibleMigration + end + + private + + def delete_notifications + Notification.where(decidim_resource_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_follows + Follow.where(decidim_followable_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_reports + Moderation.where(decidim_reportable_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_coauthorships + Coauthorship.where(coauthorable_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_action_logs + ActionLog.where(resource_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_comments + Comment.where(decidim_commentable_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_resource_links + ResourceLink.where(from_type: COLLABORATIVE_DRAFT_TYPE).delete_all + ResourceLink.where(to_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_categorizations + Categorization.where(categorizable_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_attachments + Attachment.where(attached_to_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_paper_trail_versions_for_collaborative_drafts + Version.where(item_type: COLLABORATIVE_DRAFT_TYPE).delete_all + end + + def delete_paper_trail_versions_for_collaborator_requests + Version.where(item_type: COLLABORATIVE_DRAFT_COLLABORATOR_REQUEST_TYPE).delete_all + end +end diff --git a/decidim-proposals/db/migrate/20171212102250_enable_pg_trgm_extension_for_proposals.rb b/decidim-proposals/db/migrate/20171212102250_enable_pg_trgm_extension_for_proposals.rb index 82d3b9a4c9b4f..c9c6bcbfc31cd 100644 --- a/decidim-proposals/db/migrate/20171212102250_enable_pg_trgm_extension_for_proposals.rb +++ b/decidim-proposals/db/migrate/20171212102250_enable_pg_trgm_extension_for_proposals.rb @@ -8,7 +8,7 @@ def change # required so that test suite works in ci env enable_extension "pg_trgm" rescue StandardError - raise <<-MSG.squish + raise <<~MSG.squish Decidim requires the pg_trgm extension to be enabled in your PostgreSQL. You can do so by running `CREATE EXTENSION IF NOT EXISTS "pg_trgm";` on the current DB as a PostgreSQL super user. diff --git a/decidim-proposals/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb b/decidim-proposals/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb index 698f60311f54e..e61d2d68ce044 100644 --- a/decidim-proposals/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb +++ b/decidim-proposals/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb @@ -2,7 +2,7 @@ class SyncProposalsStateWithAmendmentsState < ActiveRecord::Migration[5.2] def up - execute <<-SQL.squish + execute <<~SQL.squish UPDATE decidim_proposals_proposals AS proposals SET state = amendments.state FROM decidim_amendments AS amendments @@ -15,7 +15,7 @@ def up end def down - execute <<-SQL.squish + execute <<~SQL.squish UPDATE decidim_proposals_proposals AS proposals SET state = NULL FROM decidim_amendments AS amendments diff --git a/decidim-proposals/db/migrate/20200306123652_publish_existing_proposals_state.rb b/decidim-proposals/db/migrate/20200306123652_publish_existing_proposals_state.rb index 0e6a37d0366c9..69b39bbb0f5df 100644 --- a/decidim-proposals/db/migrate/20200306123652_publish_existing_proposals_state.rb +++ b/decidim-proposals/db/migrate/20200306123652_publish_existing_proposals_state.rb @@ -2,13 +2,13 @@ class PublishExistingProposalsState < ActiveRecord::Migration[5.2] def up - execute <<-SQL.squish + execute <<~SQL.squish UPDATE decidim_proposals_proposals SET state_published_at = COALESCE(answered_at, published_at) WHERE state IS NOT NULL SQL end def down - execute <<-SQL.squish + execute <<~SQL.squish UPDATE decidim_proposals_proposals SET state_published_at = NULL SQL end diff --git a/decidim-proposals/db/migrate/20200827154156_add_commentable_counter_cache_to_proposals.rb b/decidim-proposals/db/migrate/20200827154156_add_commentable_counter_cache_to_proposals.rb index 5f9159ac28fa7..ad68bb8c55711 100644 --- a/decidim-proposals/db/migrate/20200827154156_add_commentable_counter_cache_to_proposals.rb +++ b/decidim-proposals/db/migrate/20200827154156_add_commentable_counter_cache_to_proposals.rb @@ -1,12 +1,20 @@ # frozen_string_literal: true class AddCommentableCounterCacheToProposals < ActiveRecord::Migration[5.2] + class Proposal < ApplicationRecord + self.table_name = "decidim_proposals_proposals" + end + + class CollaborativeDraft < ApplicationRecord + self.table_name = "decidim_proposals_collaborative_drafts" + end + def change add_column :decidim_proposals_proposals, :comments_count, :integer, null: false, default: 0, index: true add_column :decidim_proposals_collaborative_drafts, :comments_count, :integer, null: false, default: 0, index: true - Decidim::Proposals::Proposal.reset_column_information - Decidim::Proposals::Proposal.unscoped.find_each(&:update_comments_count) - Decidim::Proposals::CollaborativeDraft.unscoped.reset_column_information - Decidim::Proposals::CollaborativeDraft.unscoped.find_each(&:update_comments_count) + Proposal.reset_column_information + Proposal.unscoped.find_each(&:update_comments_count) + CollaborativeDraft.unscoped.reset_column_information + CollaborativeDraft.unscoped.find_each(&:update_comments_count) end end diff --git a/decidim-proposals/db/migrate/20210310120812_add_followable_counter_cache_to_collaborative_drafts.rb b/decidim-proposals/db/migrate/20210310120812_add_followable_counter_cache_to_collaborative_drafts.rb index e025e2b806382..3ac3bb2817967 100644 --- a/decidim-proposals/db/migrate/20210310120812_add_followable_counter_cache_to_collaborative_drafts.rb +++ b/decidim-proposals/db/migrate/20210310120812_add_followable_counter_cache_to_collaborative_drafts.rb @@ -1,13 +1,17 @@ # frozen_string_literal: true class AddFollowableCounterCacheToCollaborativeDrafts < ActiveRecord::Migration[5.2] + class CollaborativeDraft < ApplicationRecord + self.table_name = "decidim_proposals_collaborative_drafts" + end + def change add_column :decidim_proposals_collaborative_drafts, :follows_count, :integer, null: false, default: 0, index: true reversible do |dir| dir.up do - Decidim::Proposals::CollaborativeDraft.reset_column_information - Decidim::Proposals::CollaborativeDraft.find_each do |record| + CollaborativeDraft.reset_column_information + CollaborativeDraft.find_each do |record| record.class.reset_counters(record.id, :follows) end end diff --git a/decidim-proposals/db/migrate/20250515132352_drop_collaborative_drafts_tables.rb b/decidim-proposals/db/migrate/20250515132352_drop_collaborative_drafts_tables.rb new file mode 100644 index 0000000000000..afb94a2a087cf --- /dev/null +++ b/decidim-proposals/db/migrate/20250515132352_drop_collaborative_drafts_tables.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class DropCollaborativeDraftsTables < ActiveRecord::Migration[7.2] + def up + drop_table :decidim_proposals_collaborative_drafts, if_exists: true + drop_table :decidim_proposals_collaborative_draft_collaborator_requests, if_exists: true + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/decidim-proposals/lib/decidim/proposals.rb b/decidim-proposals/lib/decidim/proposals.rb index b0a8d41e8506d..1bc4b4b9e9dd9 100644 --- a/decidim-proposals/lib/decidim/proposals.rb +++ b/decidim-proposals/lib/decidim/proposals.rb @@ -17,26 +17,27 @@ module Proposals autoload :ProposalSerializer, "decidim/proposals/proposal_serializer" autoload :DownloadYourDataProposalSerializer, "decidim/proposals/download_your_data_proposal_serializer" autoload :CommentableProposal, "decidim/proposals/commentable_proposal" - autoload :CommentableCollaborativeDraft, "decidim/proposals/commentable_collaborative_draft" autoload :MarkdownToProposals, "decidim/proposals/markdown_to_proposals" autoload :ParticipatoryTextSection, "decidim/proposals/participatory_text_section" autoload :DocToMarkdown, "decidim/proposals/doc_to_markdown" autoload :OdtToMarkdown, "decidim/proposals/odt_to_markdown" autoload :Evaluable, "decidim/proposals/evaluable" - include ActiveSupport::Configurable + class << self + def config = self + + def configure + yield self + end + end # Public Setting that defines how many proposals will be shown in the # participatory_space_highlighted_elements view hook - config_accessor :participatory_space_highlighted_proposals_limit do - Decidim::Env.new("PROPOSALS_PARTICIPATORY_SPACE_HIGHLIGHTED_PROPOSALS_LIMIT", 4).to_i - end + mattr_accessor :participatory_space_highlighted_proposals_limit, default: Decidim::Env.new("PROPOSALS_PARTICIPATORY_SPACE_HIGHLIGHTED_PROPOSALS_LIMIT", 4).to_i # Public Setting that defines how many proposals will be shown in the # process_group_highlighted_elements view hook - config_accessor :process_group_highlighted_proposals_limit do - Decidim::Env.new("PROPOSALS_PROCESS_GROUP_HIGHLIGHTED_PROPOSALS_LIMIT", 3).to_i - end + mattr_accessor :process_group_highlighted_proposals_limit, default: Decidim::Env.new("PROPOSALS_PROCESS_GROUP_HIGHLIGHTED_PROPOSALS_LIMIT", 3).to_i def self.proposal_states_colors { diff --git a/decidim-proposals/lib/decidim/proposals/admin_engine.rb b/decidim-proposals/lib/decidim/proposals/admin_engine.rb index cdd1a99fb88b3..8a7098a632560 100644 --- a/decidim-proposals/lib/decidim/proposals/admin_engine.rb +++ b/decidim-proposals/lib/decidim/proposals/admin_engine.rb @@ -23,8 +23,6 @@ class AdminEngine < ::Rails::Engine post :publish_answers post :update_multiple_answers, controller: "proposal_answers" get :manage_trash, controller: "proposals" - resource :proposals_import, only: [:new, :create] - resource :proposals_merge, only: [:new, :create] resource :proposals_split, only: [:create] resource :evaluation_assignment, only: [:create, :destroy] end @@ -36,6 +34,11 @@ class AdminEngine < ::Rails::Engine end end + resource :proposals_import, only: [:new, :create] do + get :component_states + end + resource :proposals_merge, only: [:new, :create] + resources :proposal_states resources :participatory_texts, only: [:index] do diff --git a/decidim-proposals/lib/decidim/proposals/commentable_collaborative_draft.rb b/decidim-proposals/lib/decidim/proposals/commentable_collaborative_draft.rb deleted file mode 100644 index c9b846f04761e..0000000000000 --- a/decidim-proposals/lib/decidim/proposals/commentable_collaborative_draft.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Proposals - # The data store for a Proposal in the Decidim::Proposals component. - module CommentableCollaborativeDraft - extend ActiveSupport::Concern - include Decidim::Comments::Commentable - - included do - # Public: Overrides the `commentable?` Commentable concern method. - def commentable? - component.settings.comments_enabled? - end - - # Public: Overrides the `accepts_new_comments?` Commentable concern method. - def accepts_new_comments? - commentable? && !component.current_settings.comments_blocked - end - - # Public: Overrides the `comments_have_alignment?` Commentable concern method. - def comments_have_alignment? - true - end - - # Public: Overrides the `comments_have_votes?` Commentable concern method. - def comments_have_votes? - true - end - - # Public: Override Commentable concern method `users_to_notify_on_comment_created` - def users_to_notify_on_comment_created - followers - end - end - end - end -end diff --git a/decidim-proposals/lib/decidim/proposals/component.rb b/decidim-proposals/lib/decidim/proposals/component.rb index 1137858fb8ffa..2e93c914a6f6c 100644 --- a/decidim-proposals/lib/decidim/proposals/component.rb +++ b/decidim-proposals/lib/decidim/proposals/component.rb @@ -36,12 +36,16 @@ POSSIBLE_SORT_ORDERS = %w(automatic random recent most_liked most_voted most_commented most_followed with_more_authors).freeze WITH_MORE_AUTHORS_ORDER = "with_more_authors" + MOST_COMMENTED_ORDER = "most_commented" + MOST_LIKED_ORDER = "most_liked" sort_order_choices = lambda do |context| component = context[:component] orders = POSSIBLE_SORT_ORDERS.dup - return orders.excluding(WITH_MORE_AUTHORS_ORDER) unless component && Decidim::Proposals::Proposal.with_more_authors_available?(component) + orders = orders.excluding(WITH_MORE_AUTHORS_ORDER) unless component && Decidim::Proposals::Proposal.with_more_authors_available?(component) + orders = orders.excluding(MOST_COMMENTED_ORDER) unless component && Decidim::Proposals::Proposal.most_commented_available?(component) + orders = orders.excluding(MOST_LIKED_ORDER) unless component && Decidim::Proposals::Proposal.most_liked_available?(component) orders end @@ -64,7 +68,6 @@ settings.attribute :geocoding_enabled, type: :boolean, default: false settings.attribute :attachments_allowed, type: :boolean, default: false settings.attribute :resources_permissions_enabled, type: :boolean, default: true - settings.attribute :collaborative_drafts_enabled, type: :boolean, default: false settings.attribute :participatory_texts_enabled, type: :boolean, default: false, readonly: ->(context) { Decidim::Proposals::Proposal.where(component: context[:component]).any? } @@ -110,12 +113,6 @@ resource.searchable = true end - component.register_resource(:collaborative_draft) do |resource| - resource.model_class_name = "Decidim::Proposals::CollaborativeDraft" - resource.card = "decidim/proposals/collaborative_draft" - resource.reported_content_cell = "decidim/proposals/collaborative_drafts/reported_content" - end - component.register_stat :proposals_count, primary: true, admin: false, diff --git a/decidim-proposals/lib/decidim/proposals/engine.rb b/decidim-proposals/lib/decidim/proposals/engine.rb index bab41848b2548..0dff6b36ea4ab 100644 --- a/decidim-proposals/lib/decidim/proposals/engine.rb +++ b/decidim-proposals/lib/decidim/proposals/engine.rb @@ -28,16 +28,6 @@ class Engine < ::Rails::Engine end end end - resources :collaborative_drafts, except: [:destroy] do - member do - post :request_access, controller: "collaborative_draft_collaborator_requests" - post :request_accept, controller: "collaborative_draft_collaborator_requests" - post :request_reject, controller: "collaborative_draft_collaborator_requests" - post :withdraw - post :publish - end - resources :versions, only: [:show] - end scope "/proposals" do root to: "proposals#index" end @@ -45,16 +35,12 @@ class Engine < ::Rails::Engine end initializer "decidim_proposals.register_icons" do - Decidim.icons.register(name: "Decidim::Proposals::CollaborativeDraft", icon: "draft-line", category: "activity", - description: "Collaborative draft", engine: :proposals) Decidim.icons.register(name: "Decidim::Proposals::Proposal", icon: "chat-new-line", category: "activity", description: "Proposal", engine: :proposals) Decidim.icons.register(name: "participatory_texts_item", icon: "bookmark-line", description: "Index item", category: "participatory_texts", engine: :proposals) Decidim.icons.register(name: "scan-line", icon: "scan-line", category: "system", description: "", engine: :proposals) - Decidim.icons.register(name: "edit-2-line", icon: "edit-2-line", - category: "action", description: "Edit icon for Collaborative Drafts", engine: :proposals) Decidim.icons.register(name: "bookmark-line", icon: "bookmark-line", category: "system", description: "", engine: :proposals) Decidim.icons.register(name: "arrow-right-s-fill", icon: "arrow-right-s-fill", category: "system", description: "", engine: :proposals) diff --git a/decidim-proposals/lib/decidim/proposals/seeds.rb b/decidim-proposals/lib/decidim/proposals/seeds.rb index bb176f950587b..4d9330b9bcc38 100644 --- a/decidim-proposals/lib/decidim/proposals/seeds.rb +++ b/decidim-proposals/lib/decidim/proposals/seeds.rb @@ -36,12 +36,8 @@ def call end Decidim::Comments::Seed.comments_for(proposal) - - create_collaborative_draft!(component:) end - update_traceability!(component:) - create_report!(reportable: Decidim::Proposals::Proposal.take, current_user: Decidim::User.take) hide_report!(reportable: Decidim::Proposals::Proposal.take) end @@ -74,7 +70,6 @@ def create_component! can_accumulate_votes_beyond_threshold: [true, false].sample, attachments_allowed: [true, false].sample, amendments_enabled: participatory_space.id.odd?, - collaborative_drafts_enabled: true, geocoding_enabled: [true, false].sample }, step_settings: @@ -231,54 +226,6 @@ def create_proposal_notes!(proposal:) body: ::Faker::Lorem.paragraphs(number: 2).join("\n") ) end - - def create_collaborative_draft!(component:) - n = rand(5) - state = if n > 3 - "published" - elsif n > 2 - "withdrawn" - else - "open" - end - author = Decidim::User.where(organization:).all.sample - - draft = Decidim.traceability.perform_action!("create", Decidim::Proposals::CollaborativeDraft, author) do - draft = Decidim::Proposals::CollaborativeDraft.new( - component:, - title: ::Faker::Lorem.sentence(word_count: 2), - body: ::Faker::Lorem.paragraphs(number: 2).join("\n"), - state:, - published_at: Time.current - ) - draft.coauthorships.build(author: participatory_space.organization) - draft.save! - draft - end - - case n - when 2 - authors = Decidim::User.where(organization:).all.sample(5) - authors.each do |local_author| - Decidim::Coauthorship.create(coauthorable: draft, author: local_author) - end - when 3 - author2 = Decidim::User.where(organization:).all.sample - Decidim::Coauthorship.create(coauthorable: draft, author: author2) - end - - Decidim::Comments::Seed.comments_for(draft) - end - - def update_traceability!(component:) - Decidim.traceability.update!( - Decidim::Proposals::CollaborativeDraft.all.sample, - Decidim::User.where(organization:).all.sample, - component:, - title: ::Faker::Lorem.sentence(word_count: 2), - body: ::Faker::Lorem.paragraphs(number: 2).join("\n") - ) - end end end end diff --git a/decidim-proposals/lib/decidim/proposals/test/factories.rb b/decidim-proposals/lib/decidim/proposals/test/factories.rb index 4b8a17d357d2f..e9938f126ba6d 100644 --- a/decidim-proposals/lib/decidim/proposals/test/factories.rb +++ b/decidim-proposals/lib/decidim/proposals/test/factories.rb @@ -171,23 +171,6 @@ def generate_state_title(token, skip_injection: false) end end - trait :with_collaborative_drafts_enabled do - settings do - { - collaborative_drafts_enabled: true - } - end - end - - trait :with_attachments_allowed_and_collaborative_drafts_enabled do - settings do - { - attachments_allowed: true, - collaborative_drafts_enabled: true - } - end - end - trait :with_minimum_votes_per_user do transient do minimum_votes_per_user { 3 } @@ -336,7 +319,7 @@ def generate_state_title(token, skip_injection: false) trait :participant_author do after :build do |proposal, evaluator| - proposal.coauthorships.clear + proposal.coauthorships.target.clear user = build(:user, :confirmed, organization: proposal.component.participatory_space.organization, skip_injection: evaluator.skip_injection) proposal.coauthorships.build(author: user) end @@ -344,14 +327,14 @@ def generate_state_title(token, skip_injection: false) trait :official do after :build do |proposal| - proposal.coauthorships.clear + proposal.coauthorships.target.clear proposal.coauthorships.build(author: proposal.organization) end end trait :official_meeting do after :build do |proposal, evaluator| - proposal.coauthorships.clear + proposal.coauthorships.target.clear component = build(:meeting_component, :published, participatory_space: proposal.component.participatory_space, skip_injection: evaluator.skip_injection) proposal.coauthorships.build(author: build(:meeting, :published, component:, skip_injection: evaluator.skip_injection)) end @@ -481,49 +464,6 @@ def generate_state_title(token, skip_injection: false) author { build(:user, organization: proposal.organization, skip_injection:) } end - factory :collaborative_draft, class: "Decidim::Proposals::CollaborativeDraft" do - transient do - skip_injection { false } - users { nil } - end - - title { generate_localized_title(:collaborative_draft_title, skip_injection:)["en"] } - body { generate_localized_description(:collaborative_draft_body, skip_injection:)["en"] } - component { create(:proposal_component, skip_injection:) } - address { "#{Faker::Address.street_name}, #{Faker::Address.city}" } - state { "open" } - - after(:build) do |collaborative_draft, evaluator| - if collaborative_draft.component - users = evaluator.users || [create(:user, organization: collaborative_draft.component.participatory_space.organization, skip_injection: evaluator.skip_injection)] - users.each do |user| - collaborative_draft.coauthorships.build(author: user) - end - end - end - - trait :participant_author do - after :build do |draft, evaluator| - draft.coauthorships.clear - user = build(:user, organization: draft.component.participatory_space.organization, skip_injection: evaluator.skip_injection) - draft.coauthorships.build(author: user) - end - end - - trait :published do - state { "published" } - published_at { Time.current } - end - - trait :open do - state { "open" } - end - - trait :withdrawn do - state { "withdrawn" } - end - end - factory :participatory_text, class: "Decidim::Proposals::ParticipatoryText" do transient do skip_injection { false } diff --git a/decidim-proposals/spec/cells/decidim/proposals/collaborative_draft_cell_spec.rb b/decidim-proposals/spec/cells/decidim/proposals/collaborative_draft_cell_spec.rb deleted file mode 100644 index e8eaf79eccb69..0000000000000 --- a/decidim-proposals/spec/cells/decidim/proposals/collaborative_draft_cell_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe Decidim::Proposals::CollaborativeDraftCell, type: :cell do - controller Decidim::Proposals::CollaborativeDraftsController - - subject { my_cell.call(:show) } - - let(:my_cell) { cell("decidim/proposals/collaborative_draft", collaborative_draft, context:) } - - let(:component) { create(:proposal_component, :with_collaborative_drafts_enabled) } - let(:author) { create(:user, :confirmed, organization: component.organization) } - let!(:collaborative_draft) { create(:collaborative_draft, component:) } - let(:authors) { create_list(:user, 5, organization: component.organization) } - let(:collaborative_draft_va) { create(:collaborative_draft, component:, users: authors) } - let(:context) { nil } - - before do - allow(controller).to receive(:current_user).and_return(author) - end - - context "when rendering a collaborative_draft" do - it "renders the card" do - expect(subject).to have_css('[id^="proposals__collaborative_draft"]') - end - - it "renders the collaborative_draft title and link" do - expect(subject).to have_content(collaborative_draft.title) - href = Decidim::ResourceLocatorPresenter.new(collaborative_draft).path - expect(subject).to have_link(href:) - end - - it "renders the card author" do - expect(subject).to have_content(collaborative_draft.authors.first.name) - expect(subject).to have_css("[data-author]", count: 1) - end - - describe "with coauthors" do - let(:collaborative_draft) { create(:collaborative_draft, component:, users: authors) } - - it "renders the first three authors" do - expect(subject).to have_css("[data-author]", count: 3) - end - - it "indicates number of remaining authors" do - expect(subject.find("[data-remaining-authors]")).to have_content("+2") - end - end - - context "with open state" do - let(:collaborative_draft) { create(:collaborative_draft, :open, component:) } - - it "renders the card with the .success class" do - expect(subject).to have_css(".success") - end - - it "renders the open state" do - expect(subject).to have_content("Open") - end - end - - context "with withdrawn state" do - let(:collaborative_draft) { create(:collaborative_draft, :withdrawn, component:) } - - it "renders the card with the .alert class" do - expect(subject).to have_css(".alert") - end - - it "renders the open state" do - expect(subject).to have_content("Withdrawn") - end - end - - context "with published state" do - let(:collaborative_draft) { create(:collaborative_draft, :published, component:) } - - it "renders the card with the .success class" do - expect(subject).to have_css(".success") - end - - it "renders the open state" do - within ".label" do - expect(subject).to have_content("Published") - end - end - end - end -end diff --git a/decidim-proposals/spec/cells/decidim/proposals/collaborative_drafts/reported_content_cell_spec.rb b/decidim-proposals/spec/cells/decidim/proposals/collaborative_drafts/reported_content_cell_spec.rb deleted file mode 100644 index d31628386aa05..0000000000000 --- a/decidim-proposals/spec/cells/decidim/proposals/collaborative_drafts/reported_content_cell_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim::Proposals::CollaborativeDrafts - describe ReportedContentCell, type: :cell do - controller Decidim::Proposals::CollaborativeDraftsController - - let!(:collaborative_draft) { create(:collaborative_draft, body: { "en" => "a nice body" }) } - - context "when rendering" do - it "renders the collaborative draft's body" do - html = cell("decidim/reported_content", collaborative_draft).call - expect(html).to have_content("a nice body") - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/accept_access_to_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/accept_access_to_collaborative_draft_spec.rb deleted file mode 100644 index 88322b37455a5..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/accept_access_to_collaborative_draft_spec.rb +++ /dev/null @@ -1,162 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe AcceptAccessToCollaborativeDraft do - let(:component) { create(:proposal_component) } - let(:state) { :open } - let(:collaborative_draft) { create(:collaborative_draft, state, component:, users: [author1, author2]) } - let(:id) { collaborative_draft.id } - let(:requester_user) { create(:user, :confirmed, organization: component.organization) } - let(:requester_user_id) { requester_user.id } - let(:author1) { create(:user, :confirmed, organization: component.organization) } - let(:author2) { create(:user, :confirmed, organization: component.organization) } - let(:current_user) { author1 } - let(:current_organization) { component.organization } - let(:form) { AcceptAccessToCollaborativeDraftForm.from_params(form_params).with_context(current_user:, current_organization:) } - let(:form_params) do - { - state:, - id:, - requester_user_id: - } - end - - describe "Author (current_user) accepts access to requester to collaborate" do - let(:command) { described_class.new(form, current_user) } - - before do - collaborative_draft.collaborator_requests.create!(user: requester_user) - end - - context "when the collaborative draft is open" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it "removes the requester from requestors of the collaborative draft" do - expect do - command.call - end.to change(collaborative_draft.requesters, :count).by(-1) - end - - it "adds the requester as a co-author of the collaborative draft" do - command.call - updated_draft = CollaborativeDraft.find(collaborative_draft.id) - expect(updated_draft.authors).to include(requester_user) - end - - it "notifies the requester and authors of the collaborative draft that access to requester has been accepted" do - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event: "decidim.events.proposals.collaborative_draft_access_accepted", - event_class: Decidim::Proposals::CollaborativeDraftAccessAcceptedEvent, - resource: collaborative_draft, - affected_users: collaborative_draft.notifiable_identities - [requester_user], - extra: { - requester_id: requester_user_id - } - ) - - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event: "decidim.events.proposals.collaborative_draft_access_requester_accepted", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequesterAcceptedEvent, - resource: collaborative_draft, - affected_users: [requester_user] - ) - - command.call - end - end - - context "when the collaborative draft is withdrawn" do - let(:state) { :withdrawn } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not accept the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - - it "does not add the requester as a co-author of the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.authors, :count) - end - end - - context "when the collaborative draft is published" do - let(:state) { :published } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not accept the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - - it "does not add the requester as a co-author of the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.authors, :count) - end - end - - context "when the requester is missing" do - let(:requester_user_id) { nil } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not accept the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the current_user is missing" do - let(:current_user) { nil } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not accept the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the requester is not as a requestor" do - let(:not_requester_user) { create(:user, :confirmed, organization: component.organization) } - let(:requester_user_id) { not_requester_user.id } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not accept the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/admin/create_proposal_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/admin/create_proposal_spec.rb index f596535fdcff9..4146c45b5ef5d 100644 --- a/decidim-proposals/spec/commands/decidim/proposals/admin/create_proposal_spec.rb +++ b/decidim-proposals/spec/commands/decidim/proposals/admin/create_proposal_spec.rb @@ -203,7 +203,7 @@ module Admin let(:component) { create(:proposal_component, :with_attachments_allowed) } let(:uploaded_files) do [ - file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") + { file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") } ] end diff --git a/decidim-proposals/spec/commands/decidim/proposals/admin/update_proposal_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/admin/update_proposal_spec.rb index ee6bbcddcbe7b..b8bd738506565 100644 --- a/decidim-proposals/spec/commands/decidim/proposals/admin/update_proposal_spec.rb +++ b/decidim-proposals/spec/commands/decidim/proposals/admin/update_proposal_spec.rb @@ -116,7 +116,7 @@ let(:component) { create(:proposal_component, :with_attachments_allowed) } let(:uploaded_files) do [ - file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") + { file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") } ] end diff --git a/decidim-proposals/spec/commands/decidim/proposals/create_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/create_collaborative_draft_spec.rb deleted file mode 100644 index 2c674bcafd0cc..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/create_collaborative_draft_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe CreateCollaborativeDraft do - let(:form_klass) { CollaborativeDraftForm } - let(:component) { create(:proposal_component, :with_collaborative_drafts_enabled) } - let(:organization) { component.organization } - let(:user) { create(:user, :confirmed, organization:) } - let(:form) do - form_klass.from_params( - form_params - ).with_context( - current_user: user, - current_organization: organization, - current_participatory_space: component.participatory_space, - current_component: component - ) - end - - let(:author) { create(:user, organization:) } - - let(:has_address) { false } - let(:address) { nil } - let(:latitude) { 40.1234 } - let(:longitude) { 2.1234 } - let(:attachment_params) { nil } - - describe "call" do - let(:form_params) do - { - title: "This is the collaborative draft title", - body: "This is the collaborative draft body", - address:, - has_address:, - latitude:, - longitude:, - add_documents: attachment_params - } - end - - let(:command) do - described_class.new(form, author) - end - - describe "when the form is not valid" do - before do - allow(form).to receive(:invalid?).and_return(true) - end - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not create a collaborative draft" do - expect do - command.call - end.not_to change(Decidim::Proposals::CollaborativeDraft, :count) - end - end - - describe "when the form is valid" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it_behaves_like "fires an ActiveSupport::Notification event", "decidim.proposals.create_collaborative_draft:before" - it_behaves_like "fires an ActiveSupport::Notification event", "decidim.proposals.create_collaborative_draft:after" - - it "creates a new collaborative draft" do - expect do - command.call - end.to change(Decidim::Proposals::CollaborativeDraft, :count).by(1) - end - - context "with an author" do - it "sets the author" do - command.call - collaborative_draft = Decidim::Proposals::CollaborativeDraft.last - - expect(collaborative_draft.coauthorships.count).to eq(1) - expect(collaborative_draft.authors.count).to eq(1) - expect(collaborative_draft.authors.first).to eq(author) - end - end - - it "traces the action", versioning: true do - expect(Decidim.traceability) - .to receive(:perform_action!) - .with( - :create, - Decidim::Proposals::CollaborativeDraft, - user, - visibility: "public-only" - ).and_call_original - - expect { command.call }.to change(Decidim::ActionLog, :count) - action_log = Decidim::ActionLog.last - expect(action_log.version).to be_present - end - - context "when the has address checkbox is checked" do - let(:has_address) { true } - - context "when the address is present" do - let(:address) { "Some address" } - - before do - Geocoder::Lookup::Test.add_stub( - address, - [{ "latitude" => latitude, "longitude" => longitude }] - ) - end - - it "sets the latitude and longitude" do - command.call - collaborative_draft = Decidim::Proposals::CollaborativeDraft.last - - expect(collaborative_draft.latitude).to eq(latitude) - expect(collaborative_draft.longitude).to eq(longitude) - end - end - end - - context "when attachments are allowed" do - let(:component) { create(:proposal_component, :with_attachments_allowed) } - let(:attachment_params) do - [ - { - title: "My attachment", - file: upload_test_file(Decidim::Dev.asset("city.jpeg"), content_type: "image/jpeg") - } - ] - end - - it "creates an attachment for the proposal" do - expect { command.call }.to change(Decidim::Attachment, :count).by(1) - last_collaborative_draft = Decidim::Proposals::CollaborativeDraft.last - last_attachment = Decidim::Attachment.last - expect(last_attachment.attached_to).to eq(last_collaborative_draft) - end - - context "when attachment is left blank" do - let(:attachment_params) do - { - title: "" - } - end - - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - end - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/publish_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/publish_collaborative_draft_spec.rb deleted file mode 100644 index 281fca3a200f6..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/publish_collaborative_draft_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe PublishCollaborativeDraft do - let(:component) { create(:proposal_component) } - let(:taxonomies) { [create(:taxonomy, :with_parent, organization: component.organization)] } - let(:state) { :open } - let!(:collaborative_draft) { create(:collaborative_draft, component:, state:, taxonomies:) } - let!(:attachment) { Decidim::Attachment.create(attachment_params) } - let(:attachment_params) do - { - title: "My attachment", - file: Decidim::Dev.test_file("city.jpeg", "image/jpeg"), - attached_to: collaborative_draft - } - end - let(:current_user) { collaborative_draft.creator_author } - let(:command) { described_class.new(collaborative_draft, current_user) } - - describe "call" do - context "when the user is not a coauthor" do - let(:current_user) { create(:user, organization: component.organization) } - - it "broadcasts invalid" do - expect(collaborative_draft.authored_by?(current_user)).to be(false) - expect { command.call }.to broadcast(:invalid) - end - end - - context "when the resource is withdrawn" do - let(:state) { :withdrawn } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - end - - context "when the resource is published" do - let(:state) { :published } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - end - - context "when everything is ok" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it "creates a new proposal" do - expect { command.call } - .to change(Decidim::Proposals::Proposal, :count) - .by(1) - end - - it "transfers the attributes correctly" do - command.call - proposal = Decidim::Proposals::Proposal.last - - expect(proposal.taxonomies).to eq(collaborative_draft.taxonomies) - expect(proposal.address).to eq(collaborative_draft.address) - expect(proposal.attachments).to eq(collaborative_draft.attachments) - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/reject_access_to_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/reject_access_to_collaborative_draft_spec.rb deleted file mode 100644 index 2ae82cb14861f..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/reject_access_to_collaborative_draft_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe RejectAccessToCollaborativeDraft do - let(:component) { create(:proposal_component) } - let(:state) { :open } - let(:collaborative_draft) { create(:collaborative_draft, state, component:, users: [author1, author2]) } - let(:id) { collaborative_draft.id } - let(:requester_user) { create(:user, :confirmed, organization: component.organization) } - let(:requester_user_id) { requester_user.id } - let(:author1) { create(:user, :confirmed, organization: component.organization) } - let(:author2) { create(:user, :confirmed, organization: component.organization) } - let(:current_user) { author1 } - let(:current_organization) { component.organization } - let(:form) { RejectAccessToCollaborativeDraftForm.from_params(form_params).with_context(current_user:, current_organization:) } - let(:form_params) do - { - state:, - id:, - requester_user_id: - } - end - - describe "Author (current_user) rejects access to requester to collaborate" do - let(:command) { described_class.new(form, current_user) } - - before do - collaborative_draft.collaborator_requests.create!(user: requester_user) - end - - context "when the collaborative draft is open" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it "removes the requester from requestors of the collaborative draft" do - expect do - command.call - end.to change(collaborative_draft.requesters, :count).by(-1) - end - - it "notifies the requester and authors of the collaborative draft that access to requester has been rejected" do - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event: "decidim.events.proposals.collaborative_draft_access_rejected", - event_class: Decidim::Proposals::CollaborativeDraftAccessRejectedEvent, - resource: collaborative_draft, - affected_users: collaborative_draft.authors, - extra: { - requester_id: requester_user_id - } - ) - - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event: "decidim.events.proposals.collaborative_draft_access_requester_rejected", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequesterRejectedEvent, - resource: collaborative_draft, - affected_users: [requester_user] - ) - - command.call - end - end - - context "when the collaborative draft is withdrawn" do - let(:state) { :withdrawn } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not reject the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the collaborative draft is published" do - let(:state) { :published } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not reject the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the requester is missing" do - let(:requester_user_id) { nil } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not reject the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the current_user is missing" do - let(:current_user) { nil } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not reject the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the requester is not as a requestor" do - let(:not_requester) { create(:user, :confirmed, organization: component.organization) } - let(:requester_user_id) { not_requester.id } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not reject the request for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/request_access_to_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/request_access_to_collaborative_draft_spec.rb deleted file mode 100644 index 9e442af2fa588..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/request_access_to_collaborative_draft_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe RequestAccessToCollaborativeDraft do - let(:component) { create(:proposal_component) } - let(:state) { :open } - - let(:collaborative_draft) { create(:collaborative_draft, state, component:, users: [author1, author2]) } - let(:id) { collaborative_draft.id } - let(:form) { RequestAccessToCollaborativeDraftForm.from_params(form_params).with_context(current_user:) } - let(:form_params) do - { - state:, - id: - } - end - let(:current_user) { create(:user, :confirmed, organization: component.organization) } - let(:author1) { create(:user, :confirmed, organization: component.organization) } - let(:author2) { create(:user, :confirmed, organization: component.organization) } - - describe "User requests to collaborate" do - let(:command) { described_class.new(form, current_user) } - - context "when the collaborative draft is open" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it "creates a new request for the collaborative draft" do - expect do - command.call - end.to change(collaborative_draft.requesters, :count).by(1) - end - - it "notifies all authors of the collaborative_draft that access has been requested" do - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event: "decidim.events.proposals.collaborative_draft_access_requested", - event_class: Decidim::Proposals::CollaborativeDraftAccessRequestedEvent, - resource: collaborative_draft, - affected_users: collaborative_draft.authors, - extra: { - requester_id: current_user.id - } - ) - - command.call - end - end - - context "when the collaborative draft is withdrawn" do - let(:state) { :withdrawn } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not create a new requestor for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - - context "when the collaborative draft is published" do - let(:state) { :published } - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not create a new requestor for the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft.requesters, :count) - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/update_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/update_collaborative_draft_spec.rb deleted file mode 100644 index cd89f4976d601..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/update_collaborative_draft_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe UpdateCollaborativeDraft do - let(:form_klass) { CollaborativeDraftForm } - - let(:component) { create(:proposal_component) } - let(:organization) { component.organization } - let(:form) do - form_klass.from_params( - form_params - ).with_context( - current_organization: organization, - current_participatory_space: component.participatory_space, - current_component: component - ) - end - - let!(:collaborative_draft) { create(:collaborative_draft, component:, users: [author]) } - let(:author) { create(:user, organization:) } - - let(:has_address) { false } - let(:address) { nil } - let(:latitude) { 40.1234 } - let(:longitude) { 2.1234 } - - describe "call" do - let(:form_params) do - { - title: "This is the collaborative draft title", - body: "This is the collaborative draft body", - address:, - has_address: - } - end - - let(:command) do - described_class.new(form, author, collaborative_draft) - end - - describe "when the form is not valid" do - before do - allow(form).to receive(:invalid?).and_return(true) - end - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not update the proposal" do - expect do - command.call - end.not_to change(collaborative_draft, :title) - end - end - - describe "when the collaborative draft is not editable by the user" do - before do - allow(collaborative_draft).to receive(:editable_by?).and_return(false) - end - - it "broadcasts invalid" do - expect { command.call }.to broadcast(:invalid) - end - - it "does not update the collaborative draft" do - expect do - command.call - end.not_to change(collaborative_draft, :title) - end - end - - describe "when the form is valid" do - it "broadcasts ok" do - expect { command.call }.to broadcast(:ok) - end - - it_behaves_like "fires an ActiveSupport::Notification event", "decidim.proposals.update_collaborative_draft:before" - it_behaves_like "fires an ActiveSupport::Notification event", "decidim.proposals.update_collaborative_draft:after" - - it "updates the collaborative draft" do - expect do - command.call - end.to change(collaborative_draft, :title) - end - - it "creates a new version for the collaborative draft", versioning: true do - expect do - command.call - end.to change { collaborative_draft.versions.count }.by(1) - expect(collaborative_draft.versions.last.whodunnit).to eq author.to_gid.to_s - end - - context "with an author" do - it "sets the author" do - command.call - collaborative_draft = Decidim::Proposals::CollaborativeDraft.last - - expect(collaborative_draft.coauthorships.count).to eq(1) - expect(collaborative_draft.authors.count).to eq(1) - expect(collaborative_draft.authors.first).to eq(author) - end - end - - context "when geocoding is enabled" do - let(:component) { create(:proposal_component, :with_geocoding_enabled) } - - context "when the has address checkbox is checked" do - let(:has_address) { true } - - context "when the address is present" do - let(:address) { "Some address" } - - before do - stub_geocoding(address, [latitude, longitude]) - end - - it "sets the latitude and longitude" do - command.call - collaborative_draft = Decidim::Proposals::CollaborativeDraft.last - - expect(collaborative_draft.latitude).to eq(latitude) - expect(collaborative_draft.longitude).to eq(longitude) - end - end - end - end - end - end - end - end -end diff --git a/decidim-proposals/spec/commands/decidim/proposals/update_proposal_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/update_proposal_spec.rb index 1a0f380f525b2..6df0388520b10 100644 --- a/decidim-proposals/spec/commands/decidim/proposals/update_proposal_spec.rb +++ b/decidim-proposals/spec/commands/decidim/proposals/update_proposal_spec.rb @@ -146,7 +146,7 @@ module Proposals let(:component) { create(:proposal_component, :with_attachments_allowed) } let(:uploaded_files) do [ - file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") + { file: upload_test_file(Decidim::Dev.asset("Exampledocument.pdf"), content_type: "application/pdf") } ] end diff --git a/decidim-proposals/spec/commands/decidim/proposals/withdraw_collaborative_draft_spec.rb b/decidim-proposals/spec/commands/decidim/proposals/withdraw_collaborative_draft_spec.rb deleted file mode 100644 index 9da9c9d56c3f6..0000000000000 --- a/decidim-proposals/spec/commands/decidim/proposals/withdraw_collaborative_draft_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe WithdrawCollaborativeDraft do - describe "call" do - let(:component) { create(:proposal_component) } - let(:organization) { component.organization } - let!(:current_user) { create(:user, organization:) } - let(:follower) { create(:user, organization:) } - let(:other_author) { create(:user, organization:) } - let(:state) { :open } - let(:collaborative_draft) { create(:collaborative_draft, component:, state:, users: [current_user, other_author]) } - let!(:follow) { create(:follow, followable: current_user, user: follower) } - let(:event) { "decidim.events.proposals.collaborative_draft_withdrawn" } - let(:event_class) { Decidim::Proposals::CollaborativeDraftWithdrawnEvent } - - it "broadcasts ok" do - expect { described_class.call(collaborative_draft, current_user) }.to broadcast(:ok) - end - - it "broadcasts invalid when the user is not a coauthor" do - expect { described_class.call(collaborative_draft, follower) }.to broadcast(:invalid) - end - - context "when the resource is withdrawn" do - let(:state) { :withdrawn } - - it "broadcasts invalid" do - expect { described_class.call(collaborative_draft, follower) }.to broadcast(:invalid) - end - end - - context "when the resource is published" do - let(:state) { :published } - - it "broadcasts invalid" do - expect { described_class.call(collaborative_draft, follower) }.to broadcast(:invalid) - end - end - - describe "events" do - subject do - described_class.new(collaborative_draft, current_user) - end - - it "notifies the collaborative draft is withdrawn to coauthors" do - affected_users = collaborative_draft.authors - [current_user] - expect(Decidim::EventsManager) - .to receive(:publish) - .with( - event:, - event_class:, - resource: collaborative_draft, - affected_users: affected_users.uniq, - extra: { - author_id: current_user.id - } - ).ordered - subject.call - end - end - end - end - end -end diff --git a/decidim-proposals/spec/controllers/concerns/orderable_spec.rb b/decidim-proposals/spec/controllers/concerns/orderable_spec.rb index 6ca3afd14e201..26138944e3379 100644 --- a/decidim-proposals/spec/controllers/concerns/orderable_spec.rb +++ b/decidim-proposals/spec/controllers/concerns/orderable_spec.rb @@ -24,7 +24,6 @@ class OrderableFakeController < Decidim::ApplicationController votes_enabled?: votes_enabled, votes_blocked?: votes_blocked, votes_hidden?: votes_hidden, - likes_enabled?: likes_enabled, comments_enabled?: comments_enabled) end let(:component_default_sort_order) { "automatic" } @@ -56,6 +55,7 @@ class OrderableFakeController < Decidim::ApplicationController context "when step has default_sort_order" do let(:component_default_sort_order) { "random" } let(:step_default_sort_order) { "most_commented" } + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } it "use it instead of component's" do expect(controller.send(:default_order)).to eq("most_commented") @@ -110,8 +110,18 @@ class OrderableFakeController < Decidim::ApplicationController let(:default_sort_order) { "most_liked" } let(:likes_enabled) { true } - it "default_order is most_liked" do - expect(controller.send(:default_order)).to eq(default_sort_order) + context "when there are no proposals with likes" do + it "defaults to random" do + expect(controller.send(:default_order)).to eq("random") + end + end + + context "when there are proposals with likes" do + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + + it "default_order is most_liked" do + expect(controller.send(:default_order)).to eq(default_sort_order) + end end end @@ -119,8 +129,18 @@ class OrderableFakeController < Decidim::ApplicationController let(:default_sort_order) { "most_commented" } let(:comments_enabled) { true } - it "default_order is most_commented" do - expect(controller.send(:default_order)).to eq(default_sort_order) + context "when there are no proposals with comments" do + it "defaults to random" do + expect(controller.send(:default_order)).to eq("random") + end + end + + context "when there are proposals with comments" do + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + it "default_order is most_commented" do + expect(controller.send(:default_order)).to eq(default_sort_order) + end end end @@ -184,6 +204,7 @@ class OrderableFakeController < Decidim::ApplicationController context "with likes enabled" do let(:likes_enabled) { true } + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } it "shows most_liked option to sort" do expect(view.available_orders).to include("most_liked") @@ -198,8 +219,31 @@ class OrderableFakeController < Decidim::ApplicationController end end + context "with or without likes and most_liked availability" do + let!(:proposal_without_likes) { create(:proposal, component:) } + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + let(:likes_enabled) { true } + + context "when there are no proposals with likes" do + before do + proposal_with_likes.update!(likes_count: 0) + end + + it "does not show most_liked option to sort" do + expect(view.available_orders).not_to include("most_liked") + end + end + + context "when there are proposals with likes" do + it "shows most_liked option to sort" do + expect(view.available_orders).to include("most_liked") + end + end + end + context "with comments enabled" do let(:comments_enabled) { true } + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } it "shows most_commented option to sort" do expect(view.available_orders).to include("most_commented") @@ -214,6 +258,28 @@ class OrderableFakeController < Decidim::ApplicationController end end + context "with or without comments and most_commented availability" do + let!(:proposal_without_comments) { create(:proposal, component:) } + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + let(:comments_enabled) { true } + + context "when there are no proposals with comments" do + before do + proposal_with_comments.update!(comments_count: 0) + end + + it "does not show most_commented option to sort" do + expect(view.available_orders).not_to include("most_commented") + end + end + + context "when there are proposals with comments" do + it "shows most_commented option to sort" do + expect(view.available_orders).to include("most_commented") + end + end + end + context "with or without coauthors and with_more_authors availability" do let!(:proposal_with_single_author) { create(:proposal, component:) } let!(:proposal_with_coauthors) { create(:proposal, component:) } @@ -278,6 +344,98 @@ class OrderableFakeController < Decidim::ApplicationController end end end + + describe "#most_commented_order_available?" do + let!(:proposal_without_comments) { create(:proposal, component:) } + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + context "when comments are disabled" do + let(:component) { create(:proposal_component, :with_comments_disabled) } + + it "returns false" do + expect(controller.send(:most_commented_order_available?)).to be false + end + end + + context "when comments are enabled" do + context "when there are proposals with only zero comments" do + before do + proposal_with_comments.update!(comments_count: 0) + end + + it "returns false" do + expect(controller.send(:most_commented_order_available?)).to be false + end + end + + context "when there are proposals with comments" do + it "returns true" do + expect(controller.send(:most_commented_order_available?)).to be true + end + end + + context "when proposals are not published" do + before do + proposal_with_comments.update!(published_at: nil) + end + + it "returns false" do + expect(controller.send(:most_commented_order_available?)).to be false + end + end + + context "when proposals are hidden" do + before do + create(:moderation, reportable: proposal_with_comments, hidden_at: Time.current) + end + + it "returns false" do + expect(controller.send(:most_commented_order_available?)).to be false + end + end + end + end + + describe "#most_liked_order_available?" do + let!(:proposal_without_likes) { create(:proposal, component:) } + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + + context "when there are proposals with only zero likes" do + before do + proposal_with_likes.update!(likes_count: 0) + end + + it "returns false" do + expect(controller.send(:most_liked_order_available?)).to be false + end + end + + context "when there are proposals with likes" do + it "returns true" do + expect(controller.send(:most_liked_order_available?)).to be true + end + end + + context "when proposals are not published" do + before do + proposal_with_likes.update!(published_at: nil) + end + + it "returns false" do + expect(controller.send(:most_liked_order_available?)).to be false + end + end + + context "when proposals are hidden" do + before do + create(:moderation, reportable: proposal_with_likes, hidden_at: Time.current) + end + + it "returns false" do + expect(controller.send(:most_liked_order_available?)).to be false + end + end + end end end end diff --git a/decidim-proposals/spec/controllers/decidim/proposals/admin/proposals_controller_spec.rb b/decidim-proposals/spec/controllers/decidim/proposals/admin/proposals_controller_spec.rb index 3f73c8072cab1..225c6b21108d9 100644 --- a/decidim-proposals/spec/controllers/decidim/proposals/admin/proposals_controller_spec.rb +++ b/decidim-proposals/spec/controllers/decidim/proposals/admin/proposals_controller_spec.rb @@ -61,7 +61,7 @@ patch(:update, params:) expect(flash[:alert]).not_to be_empty - expect(response).to have_http_status(:unprocessable_entity) + expect(response).to have_http_status(:unprocessable_content) expect(subject).to render_template(:edit) expect(response.body).to include("There was a problem saving") end diff --git a/decidim-proposals/spec/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller_spec.rb b/decidim-proposals/spec/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller_spec.rb deleted file mode 100644 index f436b375d492a..0000000000000 --- a/decidim-proposals/spec/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe CollaborativeDraftCollaboratorRequestsController do - let(:component) { create(:proposal_component, :with_creation_enabled, :with_collaborative_drafts_enabled) } - let(:params) { { component_id: component.id } } - let(:user) { create(:user, :confirmed, organization: component.organization) } - let(:author) { create(:user, :confirmed, organization: component.organization) } - let!(:collaborative_draft) { create(:collaborative_draft, component:, users: [author]) } - let(:user2) { create(:user, :confirmed, organization: component.organization) } - - before do - request.env["decidim.current_organization"] = component.organization - request.env["decidim.current_participatory_space"] = component.participatory_space - request.env["decidim.current_component"] = component - end - - describe "POST request_access" do - before do - sign_in user, scope: :user - end - - it "creates a new access request for the given collaborative_draft" do - expect { post :request_access, params: { id: collaborative_draft.id, state: collaborative_draft.state } }.to change { - collaborative_draft.reload - collaborative_draft.requesters.count - }.by(1) - - expect(response).to have_http_status(:found) - end - end - - describe "POST request_accept" do - before do - sign_in author, scope: :user - end - - it "accepts a request from another user to the given collaborative_draft" do - expect(collaborative_draft.requesters.count).to eq 0 - expect(collaborative_draft.coauthorships.count).to eq 1 - - expect(response).to have_http_status(:ok) - end - end - - describe "POST request_reject" do - before do - sign_in user2, scope: :user - post :request_access, params: { id: collaborative_draft.id, state: collaborative_draft.state } - sign_in author, scope: :user - end - - it "accepts a request from another user to the given collaborative_draft" do - expect(collaborative_draft.requesters.count).to eq 1 - - expect(response).to have_http_status(:found) - end - end - end - end -end diff --git a/decidim-proposals/spec/controllers/decidim/proposals/collaborative_drafts_controller_spec.rb b/decidim-proposals/spec/controllers/decidim/proposals/collaborative_drafts_controller_spec.rb deleted file mode 100644 index 7809a143257d8..0000000000000 --- a/decidim-proposals/spec/controllers/decidim/proposals/collaborative_drafts_controller_spec.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe CollaborativeDraftsController do - let(:component) { create(:proposal_component, :with_creation_enabled, :with_collaborative_drafts_enabled) } - let(:params) { { component_id: component.id } } - let(:user) { create(:user, :confirmed, organization: component.organization) } - let(:author) { create(:user, :confirmed, organization: component.organization) } - let!(:collaborative_draft) { create(:collaborative_draft, component:, users: [author]) } - let(:user2) { create(:user, :confirmed, organization: component.organization) } - - before do - request.env["decidim.current_organization"] = component.organization - request.env["decidim.current_participatory_space"] = component.participatory_space - request.env["decidim.current_component"] = component - end - - describe "GET index" do - context "when invoked without parameters" do - it "returns a list of open collaborative drafts by updated_at" do - get :index - - expect(response).to have_http_status(:ok) - expect(assigns[:collaborative_drafts]).not_to be_empty - expect(subject).to render_template("decidim/proposals/collaborative_drafts/index") - end - end - end - - describe "GET show" do - it "returns details of a collaborative_draft" do - get :show, params: { id: collaborative_draft.id } - - expect(response).to have_http_status(:ok) - expect(assigns(:collaborative_draft)).to be_a(Decidim::Proposals::CollaborativeDraft) - expect(subject).to render_template("decidim/proposals/collaborative_drafts/show") - end - end - - context "when creating a collaborative draft (wizard)" do - before do - sign_in user, scope: :user - end - - let(:component) { create(:proposal_component, :with_creation_enabled, :with_collaborative_drafts_enabled) } - - describe "GET new" do - it "renders the empty form" do - get(:new, params:) - expect(response).to have_http_status(:ok) - expect(subject).to render_template(:new) - end - end - end - - describe "POST create" do - let(:params) do - { - component_id: component.id, - collaborative_draft: { - title: collaborative_draft.title, - body: collaborative_draft.body - } - } - end - - context "when creation is not enabled" do - let(:component) { create(:proposal_component, :with_collaborative_drafts_enabled) } - - it "redirects" do - post(:create, params:) - expect(response).to have_http_status(:found) - end - end - - context "when creation is enabled" do - it "creates a collaborative draft" do - post(:create, params:) - expect(response).to have_http_status(:found) - end - end - end - - describe "GET edit" do - before do - sign_in author, scope: :user - end - - it "renders the edit form" do - get :edit, params: { id: collaborative_draft.id } - expect(response).to have_http_status(:ok) - expect(assigns(:collaborative_draft)).to be_a(Decidim::Proposals::CollaborativeDraft) - expect(subject).to render_template(:edit) - end - end - - describe "POST update" do - let(:params) do - { - component_id: component.id, - id: collaborative_draft.id, - collaborative_draft: { - title: Decidim::Faker::Localized.sentence, - body: Decidim::Faker::Localized.sentence(word_count: 2) - } - } - end - - it "updates the collaborative draft" do - put(:update, params:) - expect(assigns(:collaborative_draft)).to be_a(Decidim::Proposals::CollaborativeDraft) - expect(response).to have_http_status(:found) - end - end - - context "with collaborative drafts disabled" do - let(:component) { create(:proposal_component) } - - describe "GET index" do - it "renders not found page" do - expect { get :index }.to raise_error(ActionController::RoutingError) - end - end - end - end - end -end diff --git a/decidim-proposals/spec/controllers/decidim/proposals/proposals_controller_spec.rb b/decidim-proposals/spec/controllers/decidim/proposals/proposals_controller_spec.rb index 1a5b7819cc181..e742904fb1afe 100644 --- a/decidim-proposals/spec/controllers/decidim/proposals/proposals_controller_spec.rb +++ b/decidim-proposals/spec/controllers/decidim/proposals/proposals_controller_spec.rb @@ -187,7 +187,7 @@ module Proposals patch(:update, params:) expect(flash[:alert]).not_to be_empty - expect(response).to have_http_status(:unprocessable_entity) + expect(response).to have_http_status(:unprocessable_content) expect(subject).to render_template(:edit) expect(response.body).to include("There was a problem saving") end diff --git a/decidim-proposals/spec/db/data/remove_collaborative_drafts_references_spec.rb b/decidim-proposals/spec/db/data/remove_collaborative_drafts_references_spec.rb new file mode 100644 index 0000000000000..7b2ca305bb531 --- /dev/null +++ b/decidim-proposals/spec/db/data/remove_collaborative_drafts_references_spec.rb @@ -0,0 +1,245 @@ +# frozen_string_literal: true + +require "spec_helper" + +require "./db/data/20260224210316_remove_collaborative_drafts_references" + +describe RemoveCollaborativeDraftsReferences do + let(:migrator) do + described_class.new.tap do |m| + m.verbose = false + end + end + + let(:organization) { create(:organization) } + let(:user) { create(:user, organization:) } + let(:another_user) { create(:user, organization:) } + + let(:collaborative_draft_type) { "Decidim::Proposals::CollaborativeDraft" } + let(:collaborative_draft_collaborator_request_type) { "Decidim::Proposals::CollaborativeDraftCollaboratorRequest" } + let(:draft_id) { 999_999 } + let(:collaborator_request_id) { 888_888 } + + class Version < ApplicationRecord + self.table_name = "versions" + end + + describe "#up" do + context "with notifications" do + let!(:notification) do + notification = create(:notification, user:) + notification.update_column(:decidim_resource_type, collaborative_draft_type) # rubocop:disable Rails/SkipsModelValidations + notification.update_column(:decidim_resource_id, draft_id) # rubocop:disable Rails/SkipsModelValidations + notification + end + + let!(:other_notification) do + create(:notification, user:) + end + + it "deletes notifications referencing collaborative drafts" do + expect(Decidim::Notification.where(decidim_resource_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::Notification.where(decidim_resource_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other notifications intact" do + migrator.migrate(:up) + expect(Decidim::Notification.find_by(id: other_notification.id)).to be_present + end + end + + context "with follows" do + let!(:follow) do + follow = create(:follow, user:) + follow.update_column(:decidim_followable_type, collaborative_draft_type) # rubocop:disable Rails/SkipsModelValidations + follow.update_column(:decidim_followable_id, draft_id) # rubocop:disable Rails/SkipsModelValidations + follow + end + + let!(:other_follow) do + create(:follow, user: another_user) + end + + it "deletes follows referencing collaborative drafts" do + expect(Decidim::Follow.where(decidim_followable_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::Follow.where(decidim_followable_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other follows" do + migrator.migrate(:up) + expect(Decidim::Follow.find_by(id: other_follow.id)).to be_present + end + end + + context "with coauthorships" do + let!(:coauthorship) do + coauthorship = create(:coauthorship) + coauthorship.update_column(:coauthorable_type, collaborative_draft_type) # rubocop:disable Rails/SkipsModelValidations + coauthorship.update_column(:coauthorable_id, draft_id) # rubocop:disable Rails/SkipsModelValidations + coauthorship + end + + let!(:other_coauthorship) do + create(:coauthorship) + end + + it "deletes coauthorships referencing collaborative drafts" do + expect(Decidim::Coauthorship.where(coauthorable_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::Coauthorship.where(coauthorable_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other coauthorships" do + migrator.migrate(:up) + expect(Decidim::Coauthorship.find_by(id: other_coauthorship.id)).to be_present + end + end + + context "with action logs" do + let!(:action_log) do + table = "decidim_action_logs" + columns = { + decidim_organization_id: organization.id, + user_id: user.id, + user_type: "Decidim::User", + resource_type: collaborative_draft_type, + resource_id: draft_id, + action: "create", + visibility: "public-only", + created_at: Time.current, + updated_at: Time.current + } + ActiveRecord::Base.connection.execute( + "INSERT INTO #{table} (#{columns.keys.join(", ")}) VALUES (#{columns.values.map { |v| ActiveRecord::Base.connection.quote(v) }.join(", ")})" + ) + Decidim::ActionLog.last + end + + let!(:other_action_log) do + create(:action_log, user: another_user, organization:) + end + + it "deletes action logs referencing collaborative drafts" do + expect(Decidim::ActionLog.where(resource_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::ActionLog.where(resource_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other action logs" do + migrator.migrate(:up) + expect(Decidim::ActionLog.find_by(id: other_action_log.id)).to be_present + end + end + + context "with moderations (reports)" do + let!(:moderation) do + moderation = create(:moderation) + moderation.update_column(:decidim_reportable_type, collaborative_draft_type) # rubocop:disable Rails/SkipsModelValidations + moderation.update_column(:decidim_reportable_id, draft_id) # rubocop:disable Rails/SkipsModelValidations + moderation + end + + let!(:other_moderation) do + create(:moderation) + end + + it "deletes moderations referencing collaborative drafts" do + expect(Decidim::Moderation.where(decidim_reportable_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::Moderation.where(decidim_reportable_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other moderations" do + migrator.migrate(:up) + expect(Decidim::Moderation.find_by(id: other_moderation.id)).to be_present + end + end + + context "with comments" do + let!(:comment) do + comment = create(:comment) + comment.update_column(:decidim_commentable_type, collaborative_draft_type) # rubocop:disable Rails/SkipsModelValidations + comment.update_column(:decidim_commentable_id, draft_id) # rubocop:disable Rails/SkipsModelValidations + comment + end + + let!(:other_comment) do + create(:comment) + end + + it "deletes comments referencing collaborative drafts" do + expect(Decidim::Comments::Comment.where(decidim_commentable_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Decidim::Comments::Comment.where(decidim_commentable_type: collaborative_draft_type).count).to eq(0) + end + + it "keeps other comments" do + migrator.migrate(:up) + expect(Decidim::Comments::Comment.find_by(id: other_comment.id)).to be_present + end + end + + context "with paper trail versions" do + let!(:version_for_draft) do + Version.create!( + item_type: collaborative_draft_type, + item_id: draft_id, + event: "update", + whodunnit: user.id.to_s, + object: "{}", + object_changes: "{}", + created_at: Time.current + ) + end + + let!(:version_for_collaborator_request) do + Version.create!( + item_type: collaborative_draft_collaborator_request_type, + item_id: collaborator_request_id, + event: "update", + whodunnit: user.id.to_s, + object: "{}", + object_changes: "{}", + created_at: Time.current + ) + end + + let!(:other_version) do + Version.create!( + item_type: "Decidim::Proposal", + item_id: 123, + event: "update", + whodunnit: user.id.to_s, + object: "{}", + object_changes: "{}", + created_at: Time.current + ) + end + + it "deletes paper trail versions for collaborative drafts" do + expect(Version.where(item_type: collaborative_draft_type).count).to eq(1) + migrator.migrate(:up) + expect(Version.where(item_type: collaborative_draft_type).count).to eq(0) + end + + it "deletes paper trail versions for collaborator requests" do + expect(Version.where(item_type: collaborative_draft_collaborator_request_type).count).to eq(1) + migrator.migrate(:up) + expect(Version.where(item_type: collaborative_draft_collaborator_request_type).count).to eq(0) + end + + it "keeps other versions intact" do + migrator.migrate(:up) + expect(Version.find_by(id: other_version.id)).to be_present + end + end + + context "when tables are empty" do + it "does not raise an error" do + expect { migrator.migrate(:up) }.not_to raise_error + end + end + end +end diff --git a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_accepted_event_spec.rb b/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_accepted_event_spec.rb deleted file mode 100644 index a830af6ebc858..0000000000000 --- a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_accepted_event_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe Decidim::Proposals::CollaborativeDraftAccessAcceptedEvent do - include_context "when a simple event" - - let(:event_name) { "decidim.events.proposals.collaborative_draft_access_accepted" } - let(:resource) { create(:collaborative_draft, title: "It is my collaborative draft") } - let(:resource_path) { Decidim::ResourceLocatorPresenter.new(resource).path } - let(:resource_title) { resource.title } - let(:author) { resource.authors.first } - let(:author_id) { author.id } - let(:author_presenter) { Decidim::UserPresenter.new(author) } - let(:author_path) { author_presenter.profile_path } - let(:author_name) { author_presenter.name } - let(:author_nickname) { author_presenter.nickname } - let(:requester) { create(:user, :confirmed, organization: resource.organization) } - let(:requester_presenter) { Decidim::UserPresenter.new(requester) } - let(:requester_id) { requester.id } - let(:requester_name) { requester.name } - let(:requester_nickname) { requester_presenter.nickname } - let(:requester_path) { requester_presenter.profile_path } - let(:extra) { { requester_id: } } - - context "when the notification is for coauthor users" do - let(:email_subject) { "#{requester_name} has been accepted to access as a contributor of the #{resource_title}." } - let(:email_intro) { %(#{requester_name} has been accepted to access as a contributor of the #{decidim_html_escape(resource_title)} collaborative draft.) } - let(:email_outro) { %(You have received this notification because you are a collaborator of #{decidim_html_escape(resource_title)}.) } - let(:notification_title) { %(#{requester_name} #{requester_nickname} has been accepted to access as a contributor of the #{decidim_html_escape(resource_title)} collaborative draft.) } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end - - context "when the notification is for the requester" do - let(:event_name) { "decidim.events.proposals.collaborative_draft_access_requester_accepted" } - let(:email_subject) { "You have been accepted as a contributor of #{resource_title}." } - let(:email_intro) { %(You have been accepted to access as a contributor of the #{decidim_html_escape(resource_title)} collaborative draft.) } - let(:email_outro) { %(You have received this notification because you requested to become a collaborator of #{decidim_html_escape(resource_title)}.) } - let(:notification_title) { %(You have been accepted to access as a contributor of the #{decidim_html_escape(resource_title)} collaborative draft.) } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end -end diff --git a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_rejected_event_spec.rb b/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_rejected_event_spec.rb deleted file mode 100644 index 125bb7a2f379e..0000000000000 --- a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_rejected_event_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe Decidim::Proposals::CollaborativeDraftAccessRejectedEvent do - include_context "when a simple event" - - let(:event_name) { "decidim.events.proposals.collaborative_draft_access_rejected" } - let(:resource) { create(:collaborative_draft, title: "It is my collaborative draft") } - let(:resource_path) { Decidim::ResourceLocatorPresenter.new(resource).path } - let(:resource_title) { decidim_html_escape(resource.title) } - let(:author) { resource.authors.first } - let(:author_id) { author.id } - let(:author_presenter) { Decidim::UserPresenter.new(author) } - let(:author_path) { author_presenter.profile_path } - let(:author_name) { author_presenter.name } - let(:author_nickname) { author_presenter.nickname } - let(:requester) { create(:user, :confirmed, organization: resource.organization) } - let(:requester_presenter) { Decidim::UserPresenter.new(requester) } - let(:requester_id) { requester.id } - let(:requester_name) { requester.name } - let(:requester_nickname) { requester_presenter.nickname } - let(:requester_path) { requester_presenter.profile_path } - let(:extra) { { requester_id: } } - - context "when the notification is for coauthor users" do - let(:email_subject) { "#{requester_name} has been rejected to access as a contributor of the #{translated(resource.title)} collaborative draft." } - let(:email_intro) { %(#{requester_name} has been rejected to access as a contributor of the #{resource_title} collaborative draft.) } - let(:email_outro) { %(You have received this notification because you are a collaborator of #{resource_title}.) } - let(:notification_title) { %(#{requester_name} #{requester_nickname} has been rejected to access as a contributor of the #{resource_title} collaborative draft.) } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end - - context "when the notification is for the requester" do - let(:event_name) { "decidim.events.proposals.collaborative_draft_access_requester_rejected" } - let(:email_subject) { "You have been rejected as a contributor of #{translated(resource.title)}." } - let(:email_intro) { %(You have been rejected to access as a contributor of the #{resource_title} collaborative draft.) } - let(:email_outro) { %(You have received this notification because you requested to become a collaborator of #{resource_title}.) } - let(:notification_title) { %(You have been rejected to access as a contributor of the #{resource_title} collaborative draft.) } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end -end diff --git a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_requested_event_spec.rb b/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_requested_event_spec.rb deleted file mode 100644 index faa8e33bc3511..0000000000000 --- a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_access_requested_event_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe Decidim::Proposals::CollaborativeDraftAccessRequestedEvent do - include_context "when a simple event" - - let(:event_name) { "decidim.events.proposals.collaborative_draft_access_requested" } - let(:resource) { create(:collaborative_draft, title: "It is my collaborative draft") } - let(:resource_path) { Decidim::ResourceLocatorPresenter.new(resource).path } - let(:resource_title) { resource.title } - let(:author) { resource.authors.first } - let(:author_id) { author.id } - let(:author_presenter) { Decidim::UserPresenter.new(author) } - let(:author_path) { author_presenter.profile_path } - let(:author_name) { author_presenter.name } - let(:author_nickname) { author_presenter.nickname } - let(:requester) { create(:user, :confirmed, organization: resource.organization) } - let(:requester_name) { requester.name } - let(:requester_id) { requester.id } - let(:requester_presenter) { Decidim::UserPresenter.new(requester) } - let(:requester_path) { requester_presenter.profile_path } - let(:requester_nickname) { requester_presenter.nickname } - let(:extra) { { requester_id: } } - - context "when the notification is for coauthor users" do - let(:notification_title) { %(#{requester_name} #{requester_nickname} requested access to contribute to the #{decidim_html_escape(resource_title)} collaborative draft. Please accept or reject the request.) } - let(:email_outro) { %(You have received this notification because you are a collaborator of #{decidim_html_escape(resource_title)}.) } - let(:email_intro) { %(#{requester_name} requested access as a contributor. You can accept or reject the request from the #{decidim_html_escape(resource_title)} collaborative draft page.) } - let(:email_subject) { "#{requester_name} requested access to contribute to #{resource_title}." } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end -end diff --git a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_withdrawn_event_spec.rb b/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_withdrawn_event_spec.rb deleted file mode 100644 index fbfb06b153ff5..0000000000000 --- a/decidim-proposals/spec/events/decidim/proposals/collaborative_draft_withdrawn_event_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe Decidim::Proposals::CollaborativeDraftWithdrawnEvent do - include_context "when a simple event" - - let(:event_name) { "decidim.events.proposals.collaborative_draft_withdrawn" } - let(:resource) { create(:collaborative_draft, title: "It is my collaborative draft") } - let(:resource_path) { Decidim::ResourceLocatorPresenter.new(resource).path } - let(:resource_title) { decidim_html_escape(resource.title) } - let(:author) { resource.authors.first } - let(:author_id) { author.id } - let(:author_presenter) { Decidim::UserPresenter.new(author) } - let(:author_path) { author_presenter.profile_path } - let(:author_url) { author_presenter.profile_url } - let(:author_name) { author_presenter.name } - let(:author_nickname) { author_presenter.nickname } - let(:extra) { { author_id: } } - - context "when the notification is for coauthor users" do - let(:notification_title) { %(#{author_name} #{author_nickname} withdrawn the #{resource_title} collaborative draft.) } - let(:email_outro) { %(You have received this notification because you are a collaborator of #{resource_title}.) } - let(:email_intro) { %(#{author_name} #{author_nickname} withdrawn the #{resource_title} collaborative draft.) } - let(:email_subject) { "#{author_name} #{author_nickname} withdrawn the #{decidim_sanitize(resource_title)} collaborative draft." } - - it_behaves_like "a simple event" - it_behaves_like "a simple event email" - it_behaves_like "a simple event notification" - end -end diff --git a/decidim-proposals/spec/forms/decidim/proposals/admin/accept_access_to_collaborative_draft_form_spec.rb b/decidim-proposals/spec/forms/decidim/proposals/admin/accept_access_to_collaborative_draft_form_spec.rb deleted file mode 100644 index 035fb37b2fe76..0000000000000 --- a/decidim-proposals/spec/forms/decidim/proposals/admin/accept_access_to_collaborative_draft_form_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - module Admin - describe AcceptAccessToCollaborativeDraftForm do - subject { form } - - let(:organization) { create(:organization) } - let(:collaborative_draft) { create(:collaborative_draft, :open) } - let(:state) { collaborative_draft.state } - let(:id) { collaborative_draft.id } - let(:current_user) { create(:user, organization:) } - let(:requester_user) { create(:user, organization:) } - let(:requester_user_id) { requester_user.id } - let(:params) do - { - state:, - requester_user_id:, - id: - } - end - - let(:form) do - described_class.from_params(params) - end - - before do - collaborative_draft.collaborator_requests.create!(user: requester_user) - end - - context "when everything is OK" do - it { is_expected.to be_valid } - end - - context "when the state is not valid" do - let(:state) { "foo" } - - it { is_expected.to be_invalid } - end - - context "when there is no state" do - let(:state) { nil } - - it { is_expected.to be_invalid } - end - - context "when there is no collaborative_draft id" do - let(:id) { nil } - - it { is_expected.to be_invalid } - end - - context "when there is no requester user id" do - let(:requester_user_id) { nil } - - it { is_expected.to be_invalid } - end - - context "when the requester user is not a requester" do - let(:not_requester_user) { create(:user, organization:) } - let(:requester_user_id) { not_requester_user.id } - - it { is_expected.to be_invalid } - end - end - end - end -end diff --git a/decidim-proposals/spec/forms/decidim/proposals/admin/reject_access_to_collaborative_draft_form_spec.rb b/decidim-proposals/spec/forms/decidim/proposals/admin/reject_access_to_collaborative_draft_form_spec.rb deleted file mode 100644 index 1b3b9f2351fb9..0000000000000 --- a/decidim-proposals/spec/forms/decidim/proposals/admin/reject_access_to_collaborative_draft_form_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - module Admin - describe RejectAccessToCollaborativeDraftForm do - subject { form } - - let(:organization) { create(:organization) } - let(:collaborative_draft) { create(:collaborative_draft, :open) } - let(:state) { collaborative_draft.state } - let(:id) { collaborative_draft.id } - let(:current_user) { create(:user, organization:) } - let(:requester_user) { create(:user, organization:) } - let(:requester_user_id) { requester_user.id } - let(:params) do - { - state:, - requester_user_id:, - id: - } - end - - let(:form) do - described_class.from_params(params) - end - - before do - collaborative_draft.collaborator_requests.create!(user: requester_user) - end - - context "when everything is OK" do - it { is_expected.to be_valid } - end - - context "when the state is not valid" do - let(:state) { "foo" } - - it { is_expected.to be_invalid } - end - - context "when there is no state" do - let(:state) { nil } - - it { is_expected.to be_invalid } - end - - context "when there is no collaborative_draft id" do - let(:id) { nil } - - it { is_expected.to be_invalid } - end - - context "when there is no requester user id" do - let(:requester_user_id) { nil } - - it { is_expected.to be_invalid } - end - - context "when the requester user is not a requester" do - let(:not_requester_user) { create(:user, organization:) } - let(:requester_user_id) { not_requester_user.id } - - it { is_expected.to be_invalid } - end - end - end - end -end diff --git a/decidim-proposals/spec/forms/decidim/proposals/admin/request_access_to_collaborative_draft_form_spec.rb b/decidim-proposals/spec/forms/decidim/proposals/admin/request_access_to_collaborative_draft_form_spec.rb deleted file mode 100644 index b3add690d54cc..0000000000000 --- a/decidim-proposals/spec/forms/decidim/proposals/admin/request_access_to_collaborative_draft_form_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - module Admin - describe RequestAccessToCollaborativeDraftForm do - subject { form } - - let(:organization) { create(:organization) } - let(:collaborative_draft) { create(:collaborative_draft, :open) } - let(:state) { collaborative_draft.state } - let(:id) { collaborative_draft.id } - let(:current_user) { create(:user, organization:) } - let(:params) do - { - state:, - id: - } - end - - let(:form) do - described_class.from_params(params) - end - - context "when everything is OK" do - it { is_expected.to be_valid } - end - - context "when the state is not valid" do - let(:state) { "foo" } - - it { is_expected.to be_invalid } - end - - context "when there is no state" do - let(:state) { nil } - - it { is_expected.to be_invalid } - end - - context "when there is no collaborative_draft id" do - let(:id) { nil } - - it { is_expected.to be_invalid } - end - end - end - end -end diff --git a/decidim-proposals/spec/jobs/decidim/proposals/hide_all_created_by_author_job_spec.rb b/decidim-proposals/spec/jobs/decidim/proposals/hide_all_created_by_author_job_spec.rb index 097dd1bbfa0be..e9b92aeb3de88 100644 --- a/decidim-proposals/spec/jobs/decidim/proposals/hide_all_created_by_author_job_spec.rb +++ b/decidim-proposals/spec/jobs/decidim/proposals/hide_all_created_by_author_job_spec.rb @@ -12,12 +12,4 @@ let(:not_hideable) { create(:proposal, component:) } end end - - context "when collaborative_draft" do - it_behaves_like "has hideable resource" do - let(:component) { create(:proposal_component, :with_collaborative_drafts_enabled, organization:) } - let(:hideable) { create(:collaborative_draft, component:, users: [author]) } - let(:not_hideable) { create(:collaborative_draft, component:) } - end - end end diff --git a/decidim-proposals/spec/lib/decidim/proposals/component_spec.rb b/decidim-proposals/spec/lib/decidim/proposals/component_spec.rb index 863ab0ee2e9f9..5fafc6a05cc1d 100644 --- a/decidim-proposals/spec/lib/decidim/proposals/component_spec.rb +++ b/decidim-proposals/spec/lib/decidim/proposals/component_spec.rb @@ -245,6 +245,24 @@ expect(default_sort_order_container).to have_content("With more authors") end end + + context "when there are no proposals with comments" do + it "does not include most_commented" do + expect(default_sort_order_container).to have_no_content("Most commented") + end + end + + context "when there are proposals with comments" do + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + before do + visit edit_component_path + end + + it "includes most_commented" do + expect(default_sort_order_container).to have_content("Most commented") + end + end end end diff --git a/decidim-proposals/spec/lib/decidim/proposals/download_your_data_proposal_serializer_spec.rb b/decidim-proposals/spec/lib/decidim/proposals/download_your_data_proposal_serializer_spec.rb index feab4c95e11d9..91133740bcd9e 100644 --- a/decidim-proposals/spec/lib/decidim/proposals/download_your_data_proposal_serializer_spec.rb +++ b/decidim-proposals/spec/lib/decidim/proposals/download_your_data_proposal_serializer_spec.rb @@ -27,12 +27,12 @@ module Proposals let(:expected_answer) do answer = proposal.answer - Decidim.available_locales.each_with_object({}) do |locale, result| - result[locale.to_s] = if answer.is_a?(Hash) - answer[locale.to_s] || "" - else - "" - end + Decidim.available_locales.to_h do |locale| + [locale.to_s, if answer.is_a?(Hash) + answer[locale.to_s] || "" + else + "" + end] end end diff --git a/decidim-proposals/spec/lib/decidim/proposals/proposal_serializer_spec.rb b/decidim-proposals/spec/lib/decidim/proposals/proposal_serializer_spec.rb index eb47bd9270931..faa033eb10cc2 100644 --- a/decidim-proposals/spec/lib/decidim/proposals/proposal_serializer_spec.rb +++ b/decidim-proposals/spec/lib/decidim/proposals/proposal_serializer_spec.rb @@ -27,12 +27,12 @@ module Proposals let(:expected_answer) do answer = proposal.answer - Decidim.available_locales.each_with_object({}) do |locale, result| - result[locale.to_s] = if answer.is_a?(Hash) - answer[locale.to_s] || "" - else - "" - end + Decidim.available_locales.to_h do |locale| + [locale.to_s, if answer.is_a?(Hash) + answer[locale.to_s] || "" + else + "" + end] end end diff --git a/decidim-proposals/spec/models/decidim/proposals/collaborative_draft_spec.rb b/decidim-proposals/spec/models/decidim/proposals/collaborative_draft_spec.rb deleted file mode 100644 index e035e9402b304..0000000000000 --- a/decidim-proposals/spec/models/decidim/proposals/collaborative_draft_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe CollaborativeDraft do - subject { collaborative_draft } - - let(:organization) { component.participatory_space.organization } - let(:component) { create(:proposal_component) } - let(:collaborative_draft) { create(:collaborative_draft, component:) } - let(:coauthorable) { collaborative_draft } - - include_examples "coauthorable" - include_examples "has taxonomies" - include_examples "resourceable" - - it { is_expected.to be_valid } - it { is_expected.to be_versioned } - - describe "#users_to_notify_on_comment_created" do - let!(:follows) { create_list(:follow, 3, followable: subject) } - let(:followers) { follows.map(&:user) } - let(:participatory_space) { subject.component.participatory_space } - let(:organization) { participatory_space.organization } - let!(:participatory_process_admin) do - create(:process_admin, participatory_process: participatory_space) - end - - it "returns the followers" do - expect(subject.users_to_notify_on_comment_created).to match_array(followers.push(collaborative_draft.creator_author)) - end - end - - describe "#editable_by?" do - let(:author) { create(:user, organization:) } - - context "when user is author" do - let(:collaborative_draft) do - cd = create(:collaborative_draft, component:, updated_at: Time.current) - Decidim::Coauthorship.create(author:, coauthorable: cd) - cd - end - - it { is_expected.to be_editable_by(author) } - end - - context "when user is not the author" do - let(:collaborative_draft) { create(:collaborative_draft, component:, updated_at: Time.current) } - - it { is_expected.not_to be_editable_by(author) } - end - end - end - end -end diff --git a/decidim-proposals/spec/models/decidim/proposals/proposal_spec.rb b/decidim-proposals/spec/models/decidim/proposals/proposal_spec.rb index 3fa41773f57d8..3ea783b316c32 100644 --- a/decidim-proposals/spec/models/decidim/proposals/proposal_spec.rb +++ b/decidim-proposals/spec/models/decidim/proposals/proposal_spec.rb @@ -82,6 +82,113 @@ module Proposals end end + describe ".most_commented_available?" do + let(:component) { create(:proposal_component) } + + context "when comments are disabled" do + let(:component) { create(:proposal_component, :with_comments_disabled) } + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + it "returns false" do + expect(described_class.most_commented_available?(component)).to be false + end + end + + context "when comments are enabled" do + context "when there are no proposals with comments" do + let!(:proposal_without_comments) { create(:proposal, component:) } + + it "returns false" do + expect(described_class.most_commented_available?(component)).to be false + end + end + + context "when there are proposals with comments" do + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + it "returns true" do + expect(described_class.most_commented_available?(component)).to be true + end + end + + context "when proposals are not published" do + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + before do + proposal_with_comments.update!(published_at: nil) + end + + it "returns false" do + expect(described_class.most_commented_available?(component)).to be false + end + end + + context "when proposals are hidden" do + let!(:proposal_with_comments) { create(:proposal, component:, comments_count: 5) } + + before do + create(:moderation, reportable: proposal_with_comments, hidden_at: Time.current) + end + + it "returns false" do + expect(described_class.most_commented_available?(component)).to be false + end + end + end + end + + describe ".most_liked_available?" do + let(:component) { create(:proposal_component) } + + context "when there are no proposals with likes" do + let!(:proposal_without_likes) { create(:proposal, component:) } + + it "returns false" do + expect(described_class.most_liked_available?(component)).to be false + end + end + + context "when there are proposals with likes" do + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + + it "returns true" do + expect(described_class.most_liked_available?(component)).to be true + end + + context "when proposals are not published" do + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + + before do + proposal_with_likes.update!(published_at: nil) + end + + it "returns false" do + expect(described_class.most_liked_available?(component)).to be false + end + end + + context "when proposals are hidden" do + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5) } + + before do + create(:moderation, reportable: proposal_with_likes, hidden_at: Time.current) + end + + it "returns false" do + expect(described_class.most_liked_available?(component)).to be false + end + end + + context "when proposals are withdrawn" do + let!(:proposal_with_likes) { create(:proposal, component:, likes_count: 5, withdrawn_at: Time.current) } + + it "returns false" do + expect(described_class.most_liked_available?(component)).to be false + end + end + end + end + it "has a votes association returning proposal votes" do expect(subject.votes.count).to eq(0) end diff --git a/decidim-proposals/spec/presenters/decidim/proposals/collaborative_draft_presenter_spec.rb b/decidim-proposals/spec/presenters/decidim/proposals/collaborative_draft_presenter_spec.rb deleted file mode 100644 index 006f06f1ca0ec..0000000000000 --- a/decidim-proposals/spec/presenters/decidim/proposals/collaborative_draft_presenter_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -module Decidim - module Proposals - describe CollaborativeDraftPresenter, type: :helper do - subject { described_class.new(collaborative_draft) } - - let(:collaborative_draft) { build(:collaborative_draft, body: content) } - - describe "when content contains urls" do - let(:content) { <<~EOCONTENT } - Content with URLs of anchor type and text urls like https://decidim.org. - And a malicious click me - EOCONTENT - let(:result) { <<~EORESULT } - Content with URLs of anchor type and text urls like https://decidim.org. - And a malicious click me - EORESULT - - it "converts all URLs to links and strips attributes in anchors" do - expect(subject.body(links: true, strip_tags: true)).to eq(result) - end - end - end - end -end diff --git a/decidim-proposals/spec/requests/collaborative_draft_search_spec.rb b/decidim-proposals/spec/requests/collaborative_draft_search_spec.rb deleted file mode 100644 index 7989b4669ab2b..0000000000000 --- a/decidim-proposals/spec/requests/collaborative_draft_search_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -RSpec.describe "Collaborative draft search" do - include Decidim::ComponentPathHelper - - subject { response.body } - - let(:component) do - create( - :proposal_component, - :with_creation_enabled, - settings: { collaborative_drafts_enabled: true } - ) - end - let(:user) { create(:user, :confirmed, organization:) } - let(:participatory_space) { component.participatory_space } - let(:organization) { participatory_space.organization } - let(:filter_params) { {} } - - let!(:collaborative_draft1) { create(:collaborative_draft, title: { en: "A doggo" }, component:) } - let!(:collaborative_draft2) { create(:collaborative_draft, body: { en: "There is a doggo in the office" }, component:) } - let!(:collaborative_draft3) { create(:collaborative_draft, :open, component:) } - let!(:collaborative_draft4) { create(:collaborative_draft, :published, component:) } - let!(:collaborative_draft5) { create(:collaborative_draft, :withdrawn, component:) } - let!(:collaborative_draft6) { create(:collaborative_draft, component:) } - let!(:collaborative_draft7) { create(:collaborative_draft, component:) } - - let(:meetings_component) { create(:component, manifest_name: "meetings", participatory_space:) } - let(:meeting) { create(:meeting, :published, component: meetings_component) } - - let(:dummy_component) { create(:component, manifest_name: "dummy", participatory_space:) } - let(:dummy_resource) { create(:dummy_resource, component: dummy_component) } - - let(:request_path) { Decidim::EngineRouter.main_proxy(component).collaborative_drafts_path } - - before do - meeting.link_resources([collaborative_draft6], "drafts_from_meeting") - collaborative_draft6.link_resources([meeting], "drafts_from_meeting") - dummy_resource.link_resources([collaborative_draft7], "included_collaborative_drafts") - collaborative_draft7.link_resources([dummy_resource], "included_collaborative_drafts") - - get( - request_path, - params: { filter: filter_params }, - headers: { "HOST" => component.organization.host } - ) - end - - it_behaves_like "a resource search", :collaborative_draft - it_behaves_like "a resource search with taxonomies", :collaborative_draft - - it "displays all collaborative drafts except published and withdrawn without any filters" do - expect(subject).to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft7.title)) - end - - context "when searching by text" do - let(:filter_params) { { search_text_cont: "doggo" } } - - it "displays only the collaborative drafts containing the search_text" do - expect(subject).to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft7.title)) - end - end - - context "when searching by state" do - let(:filter_params) { { with_any_state: states } } - - context "and the status is open" do - let(:states) { %w(open) } - - it "displays only open collaborative drafts" do - expect(subject).to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft7.title)) - end - end - - context "and the status is withdrawn" do - let(:states) { %w(withdrawn) } - - it "displays only withdrawn collaborative drafts" do - expect(subject).not_to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft7.title)) - end - end - - context "and the status is published" do - let(:states) { %w(published) } - - it "displays only withdrawn proposals" do - expect(subject).not_to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft7.title)) - end - end - end - - context "when searching by related to" do - let(:filter_params) { { related_to: } } - - context "and related to is set to meetings" do - let(:related_to) { "Decidim::Meetings::Meeting".underscore } - - it "displays only proposals related to meetings" do - expect(subject).not_to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft7.title)) - end - end - - context "and related to is set to resources" do - let(:related_to) { "Decidim::Dev::DummyResource".underscore } - - it "displays only proposals related to resources" do - expect(subject).not_to have_escaped_html(translated(collaborative_draft1.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft2.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft3.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft4.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft5.title)) - expect(subject).not_to have_escaped_html(translated(collaborative_draft6.title)) - expect(subject).to have_escaped_html(translated(collaborative_draft7.title)) - end - end - end -end diff --git a/decidim-proposals/spec/system/admin/admin_edits_proposal_spec.rb b/decidim-proposals/spec/system/admin/admin_edits_proposal_spec.rb index f986b89f3f690..53d1bafe9a590 100644 --- a/decidim-proposals/spec/system/admin/admin_edits_proposal_spec.rb +++ b/decidim-proposals/spec/system/admin/admin_edits_proposal_spec.rb @@ -162,6 +162,33 @@ expect(page).to have_no_content("city.jpeg") end + + it "can edit a proposal with an attachment" do + visit_component_admin + within "tr[data-id='#{proposal.id}']" do + find("button[data-controller='dropdown']").click + click_on "Edit proposal" + end + + expect(page).to have_content("Update proposal") + expect(page).to have_field("proposal_title_en") + expect(page.html).to include(document.file.blob.filename.to_s) + + fill_in_i18n :proposal_title, "#proposal-title-tabs", en: "Updated proposal title with attachments" + click_on "Update" + + expect(page).to have_content("Proposal successfully updated.") + + visit_component_admin + within "tr[data-id='#{proposal.id}']" do + find("button[data-controller='dropdown']").click + click_on "Edit proposal" + end + + expect(page).to have_field("proposal_title_en", with: "Updated proposal title with attachments") + click_on "Edit attachments" + expect(page).to have_content(document.file.blob.filename.to_s) + end end end diff --git a/decidim-proposals/spec/system/admin/admin_manages_component_publication_spec.rb b/decidim-proposals/spec/system/admin/admin_manages_component_publication_spec.rb new file mode 100644 index 0000000000000..98a6e09443d7b --- /dev/null +++ b/decidim-proposals/spec/system/admin/admin_manages_component_publication_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages component publication" do + include_context "when managing a component as an admin" do + let!(:resource) { create(:proposal, :published, component:) } + + context "when cycling through publication states" do + let!(:component) { create(:proposal_component, participatory_space:) } + + include_examples "cycling through publication states" + end + + context "when component is unpublished, and admin publishes" do + let!(:component) { create(:proposal_component, :unpublished, participatory_space:) } + + include_examples "add component resources to search index" + end + + context "when component is published, and admin unpublishes" do + let!(:component) { create(:proposal_component, :published, participatory_space:) } + + include_examples "removes component resources from search index" + end + end +end diff --git a/decidim-proposals/spec/system/admin/admin_moderates_user_spec.rb b/decidim-proposals/spec/system/admin/admin_moderates_user_spec.rb index ea5719d83b895..b771a98d1ca85 100644 --- a/decidim-proposals/spec/system/admin/admin_moderates_user_spec.rb +++ b/decidim-proposals/spec/system/admin/admin_moderates_user_spec.rb @@ -9,10 +9,4 @@ let(:component) { create(:proposal_component, organization:) } let(:content) { create(:proposal, :participant_author, :published, component:) } end - it_behaves_like "hideable resource during block" do - let(:reportable) { content.reload.creator.identity } - - let(:component) { create(:proposal_component, organization:) } - let(:content) { create(:collaborative_draft, :participant_author, :published, component:) } - end end diff --git a/decidim-proposals/spec/system/admin/admin_publishes_component_spec.rb b/decidim-proposals/spec/system/admin/admin_publishes_component_spec.rb deleted file mode 100644 index dae37826efb0b..0000000000000 --- a/decidim-proposals/spec/system/admin/admin_publishes_component_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Admin publishes component" do - let(:manifest_name) { "proposals" } - let!(:resource) { create(:proposal, :official, component:) } - - include_context "when publishing and unpublishing the component" - include_context "when cycling through publication states" -end diff --git a/decidim-proposals/spec/system/admin/filter_proposals_spec.rb b/decidim-proposals/spec/system/admin/filter_proposals_spec.rb index 2003cd3c4b8ed..8253c594555a6 100644 --- a/decidim-proposals/spec/system/admin/filter_proposals_spec.rb +++ b/decidim-proposals/spec/system/admin/filter_proposals_spec.rb @@ -56,10 +56,8 @@ def proposal_without_state(token) before { visit_component_admin } STATES.each do |state| - i18n_state = I18n.t(state, scope: "decidim.admin.filters.proposals.state_eq.values") - - context "when filtering proposals by state: #{i18n_state}" do - it_behaves_like "a filtered collection", options: "State", filter: i18n_state do + context "when filtering proposals by state: #{I18n.t(state, scope: "decidim.admin.filters.proposals.state_eq.values")}" do + it_behaves_like "a filtered collection", options: "State", filter: I18n.t(state, scope: "decidim.admin.filters.proposals.state_eq.values") do let(:in_filter) { translated(proposal_with_state(state).title) } let(:not_in_filter) { translated(proposal_without_state(state).title) } end diff --git a/decidim-proposals/spec/system/admin/import_proposal_answers_spec.rb b/decidim-proposals/spec/system/admin/import_proposal_answers_spec.rb deleted file mode 100644 index ebabe9468e8c2..0000000000000 --- a/decidim-proposals/spec/system/admin/import_proposal_answers_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Import proposal answers" do - let(:organization) { create(:organization, available_locales: [:en, :ca, :es]) } - let(:component) { create(:proposal_component, organization:) } - let(:proposals) { create_list(:proposal, amount, component:) } - - let(:manifest_name) { "proposals" } - let(:participatory_space) { component.participatory_space } - let(:user) { create(:user, organization:) } - - let(:answers) do - proposals.map do |proposal| - { - id: proposal.id, - state: %w(accepted rejected evaluating).sample, - "answer/en": Faker::Lorem.sentence, - "answer/ca": Faker::Lorem.sentence, - "answer/es": Faker::Lorem.sentence - } - end - end - - let(:missing_answers) do - proposals.map do |proposal| - { - id: proposal.id, - state: %w(accepted rejected evaluating).sample, - "answer/fi": Faker::Lorem.sentence, - hello: "world" - } - end - end - - let(:amount) { rand(1..5) } - let(:json_file) { Rails.root.join("tmp/import_proposal_answers.json") } - - include_context "when managing a component as an admin" - - it_behaves_like "admin manages proposal answer imports" -end diff --git a/decidim-proposals/spec/shared/admin_manages_proposal_answer_imports_examples.rb b/decidim-proposals/spec/system/admin/import_proposals_answers_from_file_spec.rb similarity index 83% rename from decidim-proposals/spec/shared/admin_manages_proposal_answer_imports_examples.rb rename to decidim-proposals/spec/system/admin/import_proposals_answers_from_file_spec.rb index c26ed05330be2..cb3318f276c8a 100644 --- a/decidim-proposals/spec/shared/admin_manages_proposal_answer_imports_examples.rb +++ b/decidim-proposals/spec/system/admin/import_proposals_answers_from_file_spec.rb @@ -1,6 +1,44 @@ # frozen_string_literal: true -shared_examples "admin manages proposal answer imports" do +require "spec_helper" + +describe "Import proposals answers from a file" do + let(:organization) { create(:organization, available_locales: [:en, :ca, :es]) } + let(:component) { create(:proposal_component, organization:) } + let(:proposals) { create_list(:proposal, amount, component:) } + + let(:manifest_name) { "proposals" } + let(:participatory_space) { component.participatory_space } + let(:user) { create(:user, organization:) } + + let(:answers) do + proposals.map do |proposal| + { + id: proposal.id, + state: %w(accepted rejected evaluating).sample, + "answer/en": Faker::Lorem.sentence, + "answer/ca": Faker::Lorem.sentence, + "answer/es": Faker::Lorem.sentence + } + end + end + + let(:missing_answers) do + proposals.map do |proposal| + { + id: proposal.id, + state: %w(accepted rejected evaluating).sample, + "answer/fi": Faker::Lorem.sentence, + hello: "world" + } + end + end + + let(:amount) { rand(1..5) } + let(:json_file) { Rails.root.join("tmp/import_proposal_answers.json") } + + include_context "when managing a component as an admin" + before do click_on "Import" click_on "Import answers from a file" diff --git a/decidim-proposals/spec/system/admin/import_proposals_from_another_component_spec.rb b/decidim-proposals/spec/system/admin/import_proposals_from_another_component_spec.rb new file mode 100644 index 0000000000000..3fec822f4f7fe --- /dev/null +++ b/decidim-proposals/spec/system/admin/import_proposals_from_another_component_spec.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Import proposals from another component" do + let(:component) { create(:proposal_component) } + let(:participatory_space) { component.participatory_space } + let!(:origin_component) { create(:proposal_component, participatory_space:) } + let(:organization) { component.organization } + + let(:manifest_name) { "proposals" } + let(:user) { create(:user, organization:) } + + include_context "when managing a component as an admin" do + let!(:component) { create(:proposal_component, participatory_space:) } + end + + before do + click_on "Import" + click_on "Import proposals from another component" + end + + it "does not show state checkboxes before a component is selected" do + expect(page).to have_no_css("#states-container input[type='checkbox']") + end + + it "dynamically loads state checkboxes after selecting an origin component" do + within ".import_proposals" do + select origin_component.name["en"], from: "Origin component" + end + + within "#states-container" do + expect(page).to have_unchecked_field("Accepted") + expect(page).to have_unchecked_field("Rejected") + expect(page).to have_unchecked_field("Evaluating") + expect(page).to have_unchecked_field("Not answered") + end + end + + it "hides state checkboxes when the component selection is cleared" do + within ".import_proposals" do + select origin_component.name["en"], from: "Origin component" + end + + expect(page).to have_css("#states-container input[type='checkbox']") + + within ".import_proposals" do + select "Please select a component", from: "Origin component" + end + + expect(page).to have_no_css("#states-container input[type='checkbox']") + end + + context "when importing proposals filtered by state" do + let!(:accepted_proposals) { create_list(:proposal, 2, :accepted, component: origin_component) } + let!(:rejected_proposals) { create_list(:proposal, 1, :rejected, component: origin_component) } + + it "only imports proposals matching the selected state" do + within ".import_proposals" do + select origin_component.name["en"], from: "Origin component" + check "Accepted" + end + + click_on "Import proposals" + + expect(page).to have_content("The import process has started. We will let you know once it has finished.") + perform_enqueued_jobs + visit current_path + + expect(Decidim::Proposals::Proposal.where(component:).count).to eq(2) + end + end + + context "with a custom state on the origin component" do + let(:custom_title) { { "en" => "Under review" } } + let!(:custom_state) do + create(:proposal_state, component: origin_component, token: "under_review", title: custom_title) + end + + it "shows the custom state alongside the default ones" do + within ".import_proposals" do + select origin_component.name["en"], from: "Origin component" + end + + within "#states-container" do + expect(page).to have_unchecked_field("Under review") + expect(page).to have_unchecked_field("Accepted") + expect(page).to have_unchecked_field("Not answered") + end + end + + context "when importing proposals with the custom state" do + let!(:custom_state_on_target) do + create(:proposal_state, component:, token: "under_review", title: custom_title) + end + let!(:custom_proposals) { create_list(:proposal, 2, component: origin_component, state: "under_review") } + let!(:accepted_proposals) { create_list(:proposal, 1, :accepted, component: origin_component) } + + it "only imports proposals in the custom state" do + within ".import_proposals" do + select origin_component.name["en"], from: "Origin component" + check "Under review" + end + + click_on "Import proposals" + + expect(page).to have_content("The import process has started. We will let you know once it has finished.") + perform_enqueued_jobs + visit current_path + + expect(Decidim::Proposals::Proposal.where(component:).count).to eq(2) + end + end + end +end diff --git a/decidim-proposals/spec/system/admin/import_proposals_from_file_spec.rb b/decidim-proposals/spec/system/admin/import_proposals_from_file_spec.rb new file mode 100644 index 0000000000000..ad16ab64cc3a3 --- /dev/null +++ b/decidim-proposals/spec/system/admin/import_proposals_from_file_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Import proposals from a file" do + let(:manifest_name) { "proposals" } + let(:user) { create(:user, organization:) } + let(:organization) { component.organization } + let(:participatory_space) { component.participatory_space } + + include_context "when managing a component as an admin" do + let!(:component) { create(:proposal_component, participatory_space:) } + end + + before do + click_on "Import" + click_on "Import proposals from a file" + end + + it "has start import button" do + expect(page).to have_content("Import") + end + + it "returns error without a file" do + click_on "Import" + expect(page).to have_content("There is an error in this field") + end + + it "does not change proposal amount if one imported row fails" do + dynamically_attach_file(:import_file, Decidim::Dev.asset("import_proposals_broken.csv")) + + click_on "Import" + expect(page).to have_content("Found an error in the import file on line 4") + expect(Decidim::Proposals::Proposal.count).to eq(0) + end + + it "creates proposals after successfully import" do + dynamically_attach_file(:import_file, Decidim::Dev.asset("import_proposals.csv")) + click_on "Import" + expect(page).to have_content("3 proposals successfully imported") + expect(Decidim::Proposals::Proposal.count).to eq(3) + end +end diff --git a/decidim-proposals/spec/system/admin/import_proposals_spec.rb b/decidim-proposals/spec/system/admin/import_proposals_spec.rb deleted file mode 100644 index 22743839d7552..0000000000000 --- a/decidim-proposals/spec/system/admin/import_proposals_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Import proposals" do - let(:component) { create(:proposal_component) } - let(:organization) { component.organization } - - let(:manifest_name) { "proposals" } - let(:participatory_space) { component.participatory_space } - let(:user) { create(:user, organization:) } - - include_context "when managing a component as an admin" do - let!(:component) { create(:proposal_component, participatory_space:) } - end - - before do - click_on "Import" - click_on "Import proposals from a file" - end - - describe "import from a file page" do - it "has start import button" do - expect(page).to have_content("Import") - end - - it "returns error without a file" do - click_on "Import" - expect(page).to have_content("There is an error in this field") - end - - it "does not change proposal amount if one imported row fails" do - dynamically_attach_file(:import_file, Decidim::Dev.asset("import_proposals_broken.csv")) - - click_on "Import" - expect(page).to have_content("Found an error in the import file on line 4") - expect(Decidim::Proposals::Proposal.count).to eq(0) - end - - it "creates proposals after successfully import" do - dynamically_attach_file(:import_file, Decidim::Dev.asset("import_proposals.csv")) - click_on "Import" - expect(page).to have_content("3 proposals successfully imported") - expect(Decidim::Proposals::Proposal.count).to eq(3) - end - end -end diff --git a/decidim-proposals/spec/system/collaborative_draft_social_share_spec.rb b/decidim-proposals/spec/system/collaborative_draft_social_share_spec.rb deleted file mode 100644 index ef700cad3283b..0000000000000 --- a/decidim-proposals/spec/system/collaborative_draft_social_share_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" -require "decidim/core/test/shared_examples/social_share_examples" - -describe "Social shares" do - let(:organization) { create(:organization) } - let(:collaborative_draft) { create(:collaborative_draft, component:, body:) } - let!(:attachment) { create(:attachment, :with_image, attached_to: collaborative_draft, file: attachment_file) } - let(:resource) { collaborative_draft } - let(:participatory_process) { create(:participatory_process, hero_image:, organization:) } - let(:hero_image) { Decidim::Dev.test_file("city2.jpeg", "image/jpeg") } - let(:component) { create(:proposal_component, participatory_space: participatory_process, settings: { collaborative_drafts_enabled: true }) } - let(:content_block) { create(:content_block, organization:, manifest_name: :hero, scope_name: :homepage) } - let(:body) { { en: "Description

" } } - let!(:attachment_file) { Decidim::Dev.test_file("city3.jpeg", "image/jpeg") } - let(:description_image_path) { Rails.application.routes.url_helpers.rails_blob_path(description_image, only_path: true) } - let(:description_image) do - ActiveStorage::Blob.create_and_upload!( - io: File.open(Decidim::Dev.asset("city.jpeg")), - filename: "description_image.jpg", - content_type: "image/jpeg" - ) - end - let(:block_attachment_file) { Decidim::Dev.test_file("icon.png", "image/png") } - - before do - if content_block - content_block.images_container.background_image = block_attachment_file - content_block.save! - end - switch_to_host(organization.host) - end - - it_behaves_like "a social share meta tag", "city3.jpeg" - it_behaves_like "a social share widget" - it_behaves_like "a social share via QR code" do - let(:card_image) { "city3.jpeg" } - end - - context "when no attachment images" do - let!(:attachment) { nil } - - it_behaves_like "a social share meta tag", "description_image.jpg" - end - - context "when no attachments nor description images" do - let(:attachment) { nil } - let(:description_image_path) { "" } - - it_behaves_like "a social share meta tag", "city2.jpeg" - end - - context "when listing all collaborative drafts" do - let(:resource) { main_component_path(component) } - - it_behaves_like "a social share meta tag", "city2.jpeg" - end -end diff --git a/decidim-proposals/spec/system/collaborative_drafts_fields_spec.rb b/decidim-proposals/spec/system/collaborative_drafts_fields_spec.rb deleted file mode 100644 index 5eb496f3e0537..0000000000000 --- a/decidim-proposals/spec/system/collaborative_drafts_fields_spec.rb +++ /dev/null @@ -1,276 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Collaborative drafts" do - include_context "with a component" - let(:manifest_name) { "proposals" } - - let(:root_taxonomy) { create(:taxonomy, organization:) } - let!(:taxonomy) { create(:taxonomy, parent: root_taxonomy, organization:) } - let(:taxonomy_filter) { create(:taxonomy_filter, root_taxonomy:, participatory_space_manifests: [participatory_process.manifest.name]) } - let!(:taxonomy_filter_item) { create(:taxonomy_filter_item, taxonomy_filter:, taxonomy_item: taxonomy) } - let!(:user) { create(:user, :confirmed, organization:) } - let(:taxonomy_filter_ids) { [taxonomy_filter.id] } - - let(:address) { "Some address" } - let(:latitude) { 40.1234 } - let(:longitude) { 2.1234 } - - let(:collaborative_draft_title) { "More sidewalks and less roads" } - let(:collaborative_draft_body) { "Cities need more people, not more cars" } - - before do - stub_geocoding(address, [latitude, longitude]) - end - - matcher :have_author do |name| - match { |node| node.has_selector?("[data-author]", text: name) } - match_when_negated { |node| node.has_no_selector?("[data-author]", text: name) } - end - - context "when creating a new collaborative_draft" do - context "when the user is logged in" do - before do - login_as user, scope: :user - end - - context "with creation enabled" do - let!(:component) do - create(:proposal_component, - :with_creation_enabled, - manifest:, - participatory_space: participatory_process, - settings: { - collaborative_drafts_enabled: true, - taxonomy_filters: taxonomy_filter_ids - }) - end - - it "creates a new collaborative draft", :slow do - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "More sidewalks and less roads" - fill_in :collaborative_draft_body, with: "Cities need more people, not more cars" - select decidim_sanitize_translated(taxonomy.name), from: "taxonomies-#{taxonomy_filter.id}" - - find("*[type=submit]").click - end - - expect(page).to have_callout("Collaborative draft successfully created.") - expect(page).to have_content("More sidewalks and less roads") - expect(page).to have_content("Cities need more people, not more cars") - expect(page).to have_content(decidim_sanitize_translated(taxonomy.name)) - expect(page).to have_author(user.name) - end - - context "when no taxonomy filter is selected" do - let(:taxonomy_filter_ids) { [] } - - it "creates a proposal without taxonomies" do - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "More sidewalks and less roads" - fill_in :collaborative_draft_body, with: "Cities need more people, not more cars" - expect(page).to have_no_content(decidim_sanitize_translated(root_taxonomy.name)) - - find("*[type=submit]").click - end - - click_on "Publish" - - expect(page).to have_callout("Collaborative draft successfully created.") - expect(page).to have_content("More sidewalks and less roads") - expect(page).to have_content("Cities need more people, not more cars") - expect(page).to have_no_content(decidim_sanitize_translated(taxonomy.name)) - expect(page).to have_author(user.name) - end - end - - context "when there are errors on the form", :slow do - before do - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "More sidewalks and less roads" - fill_in :collaborative_draft_body, with: "Cities" - - find("*[type=submit]").click - end - end - - it "shows the form with the error message" do - expect(page).to have_content("There was a problem creating this collaborative draft.") - expect(page).to have_field(:collaborative_draft_title, with: "More sidewalks and less roads") - expect(page).to have_field(:collaborative_draft_body, with: "Cities") - end - - it "allows returning to the index" do - click_on "Back to collaborative drafts" - - expect(page).to have_content("There are no collaborative drafts yet") - end - end - - context "when geocoding is enabled" do - let!(:component) do - create(:proposal_component, - :with_creation_enabled, - manifest:, - participatory_space: participatory_process) - end - - before do - component.update!(settings: { - geocoding_enabled: true, - collaborative_drafts_enabled: true - }) - end - - it "creates a new collaborative draft", :slow do - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "More sidewalks and less roads" - fill_in :collaborative_draft_body, with: "Cities need more people, not more cars" - fill_in_geocoding :collaborative_draft_address, with: address - - find("*[type=submit]").click - end - - expect(page).to have_callout("Collaborative draft successfully created.") - expect(page).to have_content("More sidewalks and less roads") - expect(page).to have_content("Cities need more people, not more cars") - expect(page).to have_content(address) - expect(page).to have_author(user.name) - end - - it_behaves_like( - "a record with front-end geocoding address field", - Decidim::Proposals::CollaborativeDraft, - within_selector: ".new_collaborative_draft", - address_field: :collaborative_draft_address - ) do - let(:geocoded_success_message) { "Collaborative draft successfully created." } - let(:geocoded_address_value) { address } - let(:geocoded_address_coordinates) { [latitude, longitude] } - - before do - # Prepare the view for submission (other than the address field) - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "More sidewalks and less roads" - fill_in :collaborative_draft_body, with: "Cities need more people, not more cars" - end - end - end - end - - context "when the user is not authorized" do - context "and there is only an authorization required" do - before do - permissions = { - create: { - authorization_handlers: { - "dummy_authorization_handler" => { "options" => {} } - } - } - } - - component.update!(permissions:) - end - - it "redirects to the authorization form" do - visit_component - click_on "Access collaborative drafts" - click_on "New collaborative draft" - expect(page).to have_content("We need to verify your identity") - expect(page).to have_content("Verify with Example authorization") - end - end - - context "and there are more than one authorization required" do - before do - permissions = { - create: { - authorization_handlers: { - "dummy_authorization_handler" => { "options" => {} }, - "another_dummy_authorization_handler" => { "options" => {} } - } - } - } - - component.update!(permissions:) - end - - it "redirects to pending onboarding authorizations page" do - visit_component - click_on "Access collaborative drafts" - click_on "New collaborative draft" - expect(page).to have_content("You are almost ready to create a proposal") - expect(page).to have_css("a[data-verification]", count: 2) - end - end - end - - context "when attachments are allowed" do - let!(:component) do - create(:proposal_component, - :with_creation_enabled, - :with_attachments_allowed_and_collaborative_drafts_enabled, - manifest:, - participatory_space: participatory_process) - end - - it "creates a new collaborative draft with attachments" do - visit new_collaborative_draft_path - - within ".new_collaborative_draft" do - fill_in :collaborative_draft_title, with: "Collaborative draft with attachments" - fill_in :collaborative_draft_body, with: "This is my collaborative draft and I want to upload attachments." - end - - dynamically_attach_file(:collaborative_draft_documents, Decidim::Dev.asset("city.jpeg")) - - within ".new_collaborative_draft" do - find("*[type=submit]").click - end - - expect(page).to have_callout("Collaborative draft successfully created.") - - within "#panel-images" do - expect(page).to have_css("img[src*=\"city.jpeg\"]", count: 1) - end - end - end - end - - context "when creation is not enabled" do - let!(:component) do - create(:proposal_component, - :with_collaborative_drafts_enabled, - manifest:, - participatory_space: participatory_process) - end - - it "does not show the creation button" do - visit_component - click_on "Access collaborative drafts" - expect(page).to have_no_link("New collaborative draft") - end - end - end - end -end - -def new_collaborative_draft_path - visit_component - "#{current_proposal_path}/collaborative_drafts/new" -end - -def current_proposal_path - current_path.sub("/proposals", "") -end diff --git a/decidim-proposals/spec/system/collaborative_drafts_spec.rb b/decidim-proposals/spec/system/collaborative_drafts_spec.rb deleted file mode 100644 index c215d8468f879..0000000000000 --- a/decidim-proposals/spec/system/collaborative_drafts_spec.rb +++ /dev/null @@ -1,367 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Explore Collaborative Drafts", versioning: true do - include Decidim::Proposals::ApplicationHelper - include ActionView::Helpers::TextHelper - - include_context "with a component" - - let(:manifest_name) { "proposals" } - let!(:author) { create(:user, :confirmed, organization:) } - let!(:user) { create(:user, :confirmed, organization:) } - let(:participatory_process) { create(:participatory_process, :with_steps, organization:) } - let!(:component) do - create(:proposal_component, - :with_creation_enabled, - manifest:, - participatory_space: participatory_process, - organization:, - settings: { - collaborative_drafts_enabled: true, - taxonomy_filters: [taxonomy_filter.id] - }) - end - let(:root_taxonomy) { create(:taxonomy, organization:) } - let!(:taxonomy) { create(:taxonomy, skip_injection: true, parent: root_taxonomy, organization:) } - let!(:taxonomy2) { create(:taxonomy, skip_injection: true, parent: root_taxonomy, organization:) } - let!(:taxonomy3) { create(:taxonomy, skip_injection: true, parent: root_taxonomy, organization:) } - let(:taxonomies) { [taxonomy] } - let(:taxonomy_filter) { create(:taxonomy_filter, root_taxonomy:) } - let!(:taxonomy_filter_item2) { create(:taxonomy_filter_item, taxonomy_filter:, taxonomy_item: taxonomy2) } - let!(:taxonomy_filter_item3) { create(:taxonomy_filter_item, taxonomy_filter:, taxonomy_item: taxonomy3) } - let!(:collaborative_draft) { create(:collaborative_draft, :open, component:, taxonomies:, users: [author]) } - let!(:collaborative_draft_no_tags) { create(:collaborative_draft, :open, component:) } - - let!(:open_collaborative_draft) { create(:collaborative_draft, :open, component:, taxonomies:) } - let!(:withdrawn_collaborative_draft) { create(:collaborative_draft, :withdrawn, component:, taxonomies: [taxonomy2]) } - let!(:published_collaborative_draft) { create(:collaborative_draft, :published, component:, taxonomies: [taxonomy3]) } - - let(:request_access_form) { Decidim::Proposals::RequestAccessToCollaborativeDraftForm.from_params(state: collaborative_draft.state, id: collaborative_draft.id) } - let!(:other_user) { create(:user, :confirmed, organization:) } - let(:request_access_from_other_user) { Decidim::Proposals::RequestAccessToCollaborativeDraft.new(request_access_form, other_user) } - - let(:selector) { '[id^="proposals__collaborative_draft"]' } - - context "with collaborative drafts enabled" do - before do - visit main_component_path(component) - click_on "Access collaborative drafts" - end - - describe "Renders collaborative drafts index" do - it "shows Open Drafts by default" do - first ".card__list" do - expect(page).to have_css(".label.success", text: "Open") - end - within "#dropdown-menu-filters" do - expect(find(:css, "input[name='filter[with_any_state][]'][value='open']")).to be_checked - end - end - - it "renders links to each collaborative draft details" do - collaborative_drafts_count = Decidim::Proposals::CollaborativeDraft.open.where(component:).count - expect(page).to have_css(selector, count: collaborative_drafts_count) - end - - it "shows state filters" do - within "[data-filters]" do - expect(page).to have_field("All") - expect(page).to have_field("Open") - expect(page).to have_field("Withdrawn") - expect(page).to have_field("Published") - end - end - - it "shows taxonomy filters" do - within "[data-filters]" do - expect(page).to have_field("All") - [taxonomy, taxonomy2, taxonomy3].each do |tax| - expect(page).to have_field(decidim_sanitize_translated(tax.name)) - end - end - end - end - - describe "renders collaborative draft details" do - before do - click_on "proposals__collaborative_draft_#{collaborative_draft.id}" - end - - let(:html_body) { strip_tags(collaborative_draft.body).gsub(/\n/, " ").strip } - let(:stripped_body) { %(alert("collaborative_draft_body"); #{html_body}) } - - it "shows the title" do - expect(page).to have_content(collaborative_draft.title) - end - - it "shows the body" do - expect(page).to have_content(stripped_body) - end - - it "shows the state" do - expect(page).to have_css(".label", text: "Open") - end - - context "when geocoding is enabled" do - let!(:component) do - create(:proposal_component, - :with_creation_enabled, - manifest:, - participatory_space: participatory_process, - organization:, - settings: { - collaborative_drafts_enabled: true, - geocoding_enabled: true - }) - end - let!(:collaborative_draft) { create(:collaborative_draft, :open, component:, address:, taxonomies:, users: [author]) } - let(:address) { "Some address" } - let(:latitude) { 40.1234 } - let(:longitude) { 2.1234 } - - before do - stub_geocoding(address, [latitude, longitude]) - end - - it "shows the title" do - expect(page).to have_content(collaborative_draft.title) - end - - it "shows the body" do - expect(page).to have_content(stripped_body) - end - - it "shows the address" do - expect(page).to have_content(collaborative_draft.address) - end - end - - context "without taxonomies" do - before do - visit_component - click_on "Access collaborative drafts" - click_on "proposals__collaborative_draft_#{collaborative_draft_no_tags.id}" - end - - it "does not show any tag" do - expect(page).to have_no_selector("ul.tags") - end - end - - context "with a taxonomy" do - it "shows tags for taxonomy" do - expect(page).to have_css("ul.tag-container") - within "ul.tag-container" do - expect(page).to have_content(decidim_sanitize_translated(taxonomy.name)) - end - end - end - - context "when a collaborative draft has comments" do - let(:author) { create(:user, :confirmed, organization: component.organization) } - let!(:comments) { create_list(:comment, 3, commentable: collaborative_draft) } - - before do - visit current_path - end - - it "shows the comments" do - comments.each do |comment| - expect(page).to have_content(comment.body.values.first) - end - end - end - - context "when publishing as a proposal" do - before do - within "main" do - expect(page).to have_content(collaborative_draft.title) - end - login_as author, scope: :user - sleep(1) - visit current_path - within ".main-bar__links-desktop" do - expect(page).to have_css("#trigger-dropdown-account") - end - end - - it "shows the publish button" do - expect(page).to have_button(text: "Publish") - end - - context "when the publish button is clicked" do - before do - click_on "Publish" - end - - it "shows the a modal" do - within "[id$='publish-irreversible-action-modal'][aria-modal]" do - expect(page).to have_css("h3", text: "The following action is irreversible") - expect(page).to have_button(text: "Publish as a Proposal") - end - click_on "Publish as a Proposal" - expect(page).to have_content("Collaborative draft published successfully as a proposal.") - end - end - end - - context "when visits a guest user" do - it "shows an announcement to collaborate" do - within "[data-announcement]" do - expect(page).to have_css("strong", text: "collaborative draft") - end - end - end - - context "when visits an non author user" do - before do - within "main" do - expect(page).to have_content(collaborative_draft.title) - end - login_as user, scope: :user - sleep(1) - visit current_path - within ".main-bar__links-desktop" do - expect(page).to have_css("#trigger-dropdown-account") - end - end - - it "shows an announcement to collaborate" do - within "[data-announcement]" do - expect(page).to have_css("strong", text: "collaborative draft") - end - end - - it "renders a button to request access" do - expect(page).to have_button(text: "Request access") - end - - context "when the user requests access" do - before do - click_on "Request access" - expect(page).to have_button("Access requested", disabled: true) - end - - it "renders an flash informing about the request" do - expect(page).to have_css("[data-alert-box].success") - within "[data-alert-box].success" do - expect(page).to have_content("Your request to collaborate has been successfully sent") - end - end - - it "removes the announcement to collaborate" do - expect(page).to have_no_css("[data-alert-box].secondary") - end - - it "shows that access has been requested" do - expect(page).to have_css("button[disabled]", text: "Access requested") - end - - context "when the author receives the request" do - before do - within ".main-bar__links-desktop" do - expect(page).to have_css("#trigger-dropdown-account") - end - relogin_as author, scope: :user - visit current_path - within ".main-bar__links-desktop" do - expect(page).to have_css("#trigger-dropdown-account") - end - end - - it "lists the user in Collaboration Requests" do - expect(page).to have_content("Collaboration requests") - expect(page).to have_css("#request_#{user.id}") - end - - it "shows the button to accept the request" do - expect(page).to have_button(text: "Accept") - end - - it "shows the button to reject the request" do - expect(page).to have_button("Reject") - end - - context "when the request is accepted and the contributor visits the draft" do - before do - click_on "Accept" - expect(page).to have_content("@#{user.nickname} has been accepted as a collaborator successfully") - relogin_as user, scope: :user - visit current_path - expect(page).to have_css("span.main-bar__avatar") - end - - it "shows the user as a coauthor" do - expect(page).to have_css("#content div.author__coauthors .author__name", text: user.name) - end - - it "removes the announcement to collaborate" do - expect(page).to have_no_css("#new_accept_access_to_collaborative_draft_") - expect(page).to have_no_css("#new_reject_access_to_collaborative_draft_") - end - - it "does not show the buttons to publish or withdraw" do - expect(page).to have_no_button("Publish") - expect(page).to have_no_button("withdraw the draft") - end - - it "shows a button to edit" do - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - expect(page).to have_css("#collaborative_draft_edit", text: "Edit") - end - - it "does not show the Collaboration Requests from other users" do - request_access_from_other_user.call - visit current_path - - expect(page).to have_no_content("Collaboration requests") - end - end - end - end - end - - context "when the author visits the collaborative draft" do - before do - within "main" do - expect(page).to have_content(collaborative_draft.title) - end - login_as author, scope: :user - sleep(1) - visit current_path - within ".main-bar__links-desktop" do - expect(page).to have_css("#trigger-dropdown-account") - end - end - - it "removes the announcement to collaborate" do - expect(page).to have_no_css("callout") - end - - it "shows the buttons to publish or withdraw" do - expect(page).to have_button("Publish") - expect(page).to have_button("withdraw the draft") - end - - it "shows a button to edit" do - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - expect(page).to have_css("#collaborative_draft_edit", text: "Edit") - end - end - end - end - - context "with collaborative drafts disabled" do - let(:component) { create(:proposal_component, manifest:, participatory_space: participatory_process) } - - before do - visit main_component_path(component) - end - - it "does not show the Collaborative drafts access button" do - expect(page).to have_no_content("Access collaborative drafts") - end - end -end diff --git a/decidim-proposals/spec/system/collaborative_drafts_versions_spec.rb b/decidim-proposals/spec/system/collaborative_drafts_versions_spec.rb deleted file mode 100644 index 0d71c04a29b44..0000000000000 --- a/decidim-proposals/spec/system/collaborative_drafts_versions_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Explore versions", versioning: true do - include_context "with a component" - let(:component) { create(:proposal_component, :with_creation_enabled, :with_collaborative_drafts_enabled, organization:) } - - let(:manifest_name) { "proposals" } - let!(:author) { create(:user, :confirmed, organization:) } - - let(:collaborative_draft_path) do - Decidim::ResourceLocatorPresenter.new(collaborative_draft).path - end - let(:original_title) { "The original title" } - let(:edited_title) { "The edited title" } - let(:original_body) { "Original body, consequuntur cupiditate non reprehenderit est vero fugiat" } - let(:edited_body) { "Edited body, Rerum assumenda blanditiis voluptatum autem, praesentium necessitatibus est" } - let!(:collaborative_draft) { create(:collaborative_draft, component:, title: original_title, body: original_body) } - - before do - Decidim.traceability.update!( - collaborative_draft, - author, - title: edited_title, - body: edited_body - ) - visit collaborative_draft_path - end - - context "when visiting versions index" do - before do - click_on "see other versions", match: :first - end - - it "lists all versions" do - expect(page).to have_link("Version 1 of 2") - expect(page).to have_link("Version 2 of 2") - end - end - - context "when showing version" do - before do - click_on "see other versions", match: :first - - click_on("Version 2 of 2") - end - - it_behaves_like "accessible page" - - it "shows the version author and creation date" do - within ".version__author" do - expect(page).to have_content(author.name) - expect(page).to have_content(Time.zone.today.strftime("%d/%m/%Y")) - end - end - - it "shows the changed attributes" do - expect(page).to have_content("Changes at") - - within "#diff-for-title" do - expect(page).to have_content("Title") - - within ".diff > ul > .del" do - expect(page).to have_content(original_title) - end - - within ".diff > ul > .ins" do - expect(page).to have_content(edited_title) - end - end - - within "#diff-for-body" do - expect(page).to have_content("Body") - - within ".diff > ul > .del" do - expect(page).to have_content(original_body) - end - - within ".diff > ul > .ins" do - expect(page).to have_content(edited_body) - end - end - end - end - - context "when visiting the collaborative draft details" do - before do - Decidim.traceability.update!( - collaborative_draft, - author, - title: "Edited title another time" - ) - visit collaborative_draft_path - end - - it "shows number of versions" do - expect(page).to have_content("(of #{collaborative_draft.versions.count})") - end - end -end diff --git a/decidim-proposals/spec/system/edit_collaborative_draft_spec.rb b/decidim-proposals/spec/system/edit_collaborative_draft_spec.rb deleted file mode 100644 index b36105d6f66c3..0000000000000 --- a/decidim-proposals/spec/system/edit_collaborative_draft_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Edit collaborative_drafts" do - include_context "with a component" - let!(:component) { create(:proposal_component, :with_collaborative_drafts_enabled, organization:) } - let(:manifest_name) { "proposals" } - - let!(:user) { create(:user, :confirmed, organization: participatory_process.organization) } - let!(:another_user) { create(:user, :confirmed, organization: participatory_process.organization) } - let!(:collaborative_draft) { create(:collaborative_draft, users: [user], component:) } - - before do - switch_to_host user.organization.host - end - - describe "editing my own collaborative draft" do - let(:new_title) { "This is my collaborative_draft new title" } - let(:new_body) { "This is my collaborative_draft new body" } - - before do - login_as user, scope: :user - end - - it "can be updated" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - click_on "Edit" - - expect(page).to have_content "Edit collaborative draft" - - within "form.edit_collaborative_draft" do - fill_in :collaborative_draft_title, with: new_title - fill_in :collaborative_draft_body, with: new_body - click_on "Send" - end - - expect(page).to have_content(new_title) - expect(page).to have_content(new_body) - end - - context "when attachment is enabled" do - context "and after collaborative draft creation" do - let!(:component) do - create(:proposal_component, - :with_attachments_allowed_and_collaborative_drafts_enabled, - manifest:, - participatory_space: participatory_process) - end - - it "can be updated" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - click_on "Edit" - - dynamically_attach_file(:collaborative_draft_documents, Decidim::Dev.asset("city.jpeg")) - - within "form.edit_collaborative_draft" do - find("*[type=submit]").click - end - - expect(page).to have_callout("Collaborative draft successfully updated.") - end - end - end - - context "when rich text editor is enabled" do - before do - organization.update(rich_text_editor_in_public_views: true) - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - click_on "Edit" - end - - it_behaves_like "having a rich text editor", "edit_collaborative_draft", "basic" - end - - context "when updating with wrong data" do - it "returns an error message" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - click_on "Edit" - - within "form.edit_collaborative_draft" do - fill_in :collaborative_draft_body, with: "A" - click_on "Send" - end - - # The character counters are doubled because there is a separate screen reader character counter. - expect(page).to have_content("At least 15 characters", count: 4) - - within "form.edit_collaborative_draft" do - fill_in :collaborative_draft_body, with: "WE DO NOT WANT TO SHOUT IN THE PROPOSAL BODY TEXT!" - click_on "Send" - end - - expect(page).to have_content("is using too many capital letters (over 25% of the text)") - end - - it "keeps the submitted values" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - find("#dropdown-trigger-resource-#{collaborative_draft.id}").click - click_on "Edit" - - within "form.edit_collaborative_draft" do - fill_in :collaborative_draft_title, with: "A draft with a title" - fill_in :collaborative_draft_body, with: "ỲÓÜ WÄNTt TÙ ÚPDÀTÉ À PRÖPÔSÁL or a COLLABORATIVE DRAFT" - end - click_on "Send" - - expect(page).to have_css("input[value='A draft with a title']") - expect(page).to have_content("ỲÓÜ WÄNTt TÙ ÚPDÀTÉ À PRÖPÔSÁL") - end - end - end - - describe "editing someone else's proposal" do - before do - login_as another_user, scope: :user - end - - it "renders an error" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - expect(page).to have_no_content("Edit collaborative draft") - visit "#{current_path}/edit" - - expect(page).to have_content("not authorized") - end - end - - describe "editing my proposal outside the time limit" do - let!(:collaborative_draft) { create(:collaborative_draft, users: [user], component:, created_at: 1.hour.ago) } - - before do - login_as another_user, scope: :user - end - - it "renders an error" do - visit_component - - click_on "Access collaborative drafts" - click_on collaborative_draft.title - expect(page).to have_no_content("Edit collaborative draft") - visit "#{current_path}/edit" - - expect(page).to have_content("not authorized") - end - end -end diff --git a/decidim-proposals/spec/system/filter_proposals_spec.rb b/decidim-proposals/spec/system/filter_proposals_spec.rb index 6fb3d3cbfb765..a6a2ac0e53265 100644 --- a/decidim-proposals/spec/system/filter_proposals_spec.rb +++ b/decidim-proposals/spec/system/filter_proposals_spec.rb @@ -170,11 +170,17 @@ end it "can be ordered by most commented and most followed after filtering" do + within "#dropdown-menu-filters div.filter-container", text: "Status" do + uncheck "All" + end + within "#dropdown-menu-filters div.filter-container", text: "Taxonomy name" do uncheck "All" check decidim_sanitize_translated(taxonomy.name) end + expect(page).to have_css("[id^='proposals__proposal']", count: 2) + within "#dropdown-menu-order" do click_on "Most commented" end diff --git a/decidim-proposals/spec/system/fingerprint_proposal_spec.rb b/decidim-proposals/spec/system/fingerprint_proposal_spec.rb index e37238cb801aa..900a4a74118f2 100644 --- a/decidim-proposals/spec/system/fingerprint_proposal_spec.rb +++ b/decidim-proposals/spec/system/fingerprint_proposal_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe "Fingerprint proposal" do +describe "Fingerprint proposal", versioning: true do let(:manifest_name) { "proposals" } let!(:fingerprintable) do diff --git a/decidim-proposals/spec/system/proposals_social_share_spec.rb b/decidim-proposals/spec/system/proposals_social_share_spec.rb index a0ed831c3ec68..99ead00f5b3a8 100644 --- a/decidim-proposals/spec/system/proposals_social_share_spec.rb +++ b/decidim-proposals/spec/system/proposals_social_share_spec.rb @@ -7,7 +7,7 @@ let(:organization) { create(:organization) } let(:participatory_process) { create(:participatory_process, hero_image:, organization:) } let(:hero_image) { Decidim::Dev.test_file("city2.jpeg", "image/jpeg") } - let(:component) { create(:proposal_component, participatory_space: participatory_process, settings: { collaborative_drafts_enabled: true }) } + let(:component) { create(:proposal_component, participatory_space: participatory_process) } let(:proposal) { create(:proposal, component:, body:) } let(:content_block) { create(:content_block, organization:, manifest_name: :hero, scope_name: :homepage) } let!(:attachment) { create(:attachment, :with_image, attached_to: proposal, file: attachment_file) } @@ -58,7 +58,7 @@ end context "when the resource's component is not published" do - let(:component) { create(:proposal_component, :unpublished, participatory_space: participatory_process, settings: { collaborative_drafts_enabled: true }) } + let(:component) { create(:proposal_component, :unpublished, participatory_space: participatory_process) } let(:proposal) { create(:proposal, :published, component:, body:) } it_behaves_like "a 404 page" do diff --git a/decidim-proposals/spec/system/proposals_spec.rb b/decidim-proposals/spec/system/proposals_spec.rb index 5aac74a1b67b9..9cfa60bea0e6d 100644 --- a/decidim-proposals/spec/system/proposals_spec.rb +++ b/decidim-proposals/spec/system/proposals_spec.rb @@ -4,6 +4,7 @@ describe "Proposals" do include ActionView::Helpers::TextHelper + include_context "with a component" let(:manifest_name) { "proposals" } @@ -664,6 +665,38 @@ end end + context "when there are no proposals with comments" do + let!(:proposals) { create_list(:proposal, 3, component:) } + + before do + visit_component + end + + it "does not show 'most_commented' ordering option" do + within ".order-by" do + expect(page).to have_css("div.order-by a", text: "Random") + page.find("a", text: "Random").click + expect(page).to have_no_content("Most commented") + end + end + end + + context "when there are no proposals with likes" do + let!(:proposals) { create_list(:proposal, 3, component:) } + + before do + visit_component + end + + it "does not show 'most_liked' ordering option" do + within ".order-by" do + expect(page).to have_css("div.order-by a", text: "Random") + page.find("a", text: "Random").click + expect(page).to have_no_content("Most liked") + end + end + end + context "when searching proposals" do let!(:proposals) do [ diff --git a/decidim-surveys/app/cells/decidim/surveys/survey_card_metadata_cell.rb b/decidim-surveys/app/cells/decidim/surveys/survey_card_metadata_cell.rb index c8d5b42712db2..412a9cbf3b9f4 100644 --- a/decidim-surveys/app/cells/decidim/surveys/survey_card_metadata_cell.rb +++ b/decidim-surveys/app/cells/decidim/surveys/survey_card_metadata_cell.rb @@ -31,7 +31,7 @@ def duration end def questions_count_item - text = "#{survey.questionnaire.questions.not_separator.size} #{t("questions", scope: "decidim.surveys.surveys.show")}" + text = "#{survey.questionnaire.question_types.size} #{t("questions", scope: "decidim.surveys.surveys.show")}" { text:, diff --git a/decidim-surveys/app/cells/decidim/surveys/survey_cell.rb b/decidim-surveys/app/cells/decidim/surveys/survey_cell.rb index d71e8d49213d7..7a9ea2c640cb2 100644 --- a/decidim-surveys/app/cells/decidim/surveys/survey_cell.rb +++ b/decidim-surveys/app/cells/decidim/surveys/survey_cell.rb @@ -14,12 +14,7 @@ def show private def card_size - case @options[:size] - when :s - "decidim/surveys/survey_s" - else - "decidim/surveys/survey_l" - end + "decidim/surveys/survey_l" end end end diff --git a/decidim-surveys/app/cells/decidim/surveys/survey_s_cell.rb b/decidim-surveys/app/cells/decidim/surveys/survey_s_cell.rb deleted file mode 100644 index 297f36df27067..0000000000000 --- a/decidim-surveys/app/cells/decidim/surveys/survey_s_cell.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require "cell/partial" - -module Decidim - module Surveys - # This cell renders the Search (:s) survey card - # for a given instance of a Survey - class SurveySCell < Decidim::CardSCell - private - - def title - present(model).title(html_escape: true) - end - - def metadata_cell - "decidim/surveys/survey_card_metadata" - end - end - end -end diff --git a/decidim-surveys/app/controllers/decidim/surveys/admin/publish_responses_controller.rb b/decidim-surveys/app/controllers/decidim/surveys/admin/publish_responses_controller.rb index a3c58b1d2e419..c06363bcc7ecd 100644 --- a/decidim-surveys/app/controllers/decidim/surveys/admin/publish_responses_controller.rb +++ b/decidim-surveys/app/controllers/decidim/surveys/admin/publish_responses_controller.rb @@ -24,7 +24,7 @@ def update end on(:invalid) do - render json: {}, status: :unprocessable_entity + render json: {}, status: :unprocessable_content end end end @@ -38,7 +38,7 @@ def destroy end on(:invalid) do - render json: {}, status: :unprocessable_entity + render json: {}, status: :unprocessable_content end end end diff --git a/decidim-surveys/app/controllers/decidim/surveys/admin/settings/surveys_controller.rb b/decidim-surveys/app/controllers/decidim/surveys/admin/settings/surveys_controller.rb index 3547714873941..12cb3806e31d5 100644 --- a/decidim-surveys/app/controllers/decidim/surveys/admin/settings/surveys_controller.rb +++ b/decidim-surveys/app/controllers/decidim/surveys/admin/settings/surveys_controller.rb @@ -25,7 +25,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.surveys.admin.surveys") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end diff --git a/decidim-surveys/app/controllers/decidim/surveys/admin/surveys_controller.rb b/decidim-surveys/app/controllers/decidim/surveys/admin/surveys_controller.rb index 416bf6332d631..13cbf4aac1713 100644 --- a/decidim-surveys/app/controllers/decidim/surveys/admin/surveys_controller.rb +++ b/decidim-surveys/app/controllers/decidim/surveys/admin/surveys_controller.rb @@ -29,7 +29,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("create.invalid", scope: "decidim.surveys.admin.surveys") - render action: "new", status: :unprocessable_entity + render action: "new", status: :unprocessable_content end end end @@ -51,7 +51,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("update.invalid", scope: "decidim.surveys.admin.surveys") - render action: "edit", status: :unprocessable_entity + render action: "edit", status: :unprocessable_content end end end @@ -66,7 +66,7 @@ def publish on(:invalid) do flash.now[:alert] = I18n.t("publish.invalid", scope: "decidim.surveys.admin.surveys") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end @@ -81,7 +81,7 @@ def unpublish on(:invalid) do flash.now[:alert] = I18n.t("unpublish.invalid", scope: "decidim.surveys.admin.surveys") - render action: "index", status: :unprocessable_entity + render action: "index", status: :unprocessable_content end end end diff --git a/decidim-surveys/app/mailers/decidim/surveys/survey_confirmation_mailer.rb b/decidim-surveys/app/mailers/decidim/surveys/survey_confirmation_mailer.rb index c44435e1879e6..eea57639d5767 100644 --- a/decidim-surveys/app/mailers/decidim/surveys/survey_confirmation_mailer.rb +++ b/decidim-surveys/app/mailers/decidim/surveys/survey_confirmation_mailer.rb @@ -4,6 +4,7 @@ module Decidim module Surveys class SurveyConfirmationMailer < ApplicationMailer include TranslatableAttributes + helper Decidim::SanitizeHelper def confirmation(user, questionnaire, responses) diff --git a/decidim-surveys/app/models/decidim/surveys/survey.rb b/decidim-surveys/app/models/decidim/surveys/survey.rb index bfba6f6b2cdca..0809ff522d452 100644 --- a/decidim-surveys/app/models/decidim/surveys/survey.rb +++ b/decidim-surveys/app/models/decidim/surveys/survey.rb @@ -9,6 +9,7 @@ class Survey < Surveys::ApplicationRecord include Decidim::HasComponent include Decidim::FilterableResource include Decidim::Publicable + include Decidim::Searchable component_manifest_name "surveys" @@ -37,6 +38,15 @@ class Survey < Surveys::ApplicationRecord scope_search_multi :with_any_state, [:open, :closed] + searchable_fields({ + participatory_space: { component: :participatory_space }, + A: :title, + D: :description, + datetime: :starts_at + }, + index_on_create: ->(survey) { survey.visible? }, + index_on_update: ->(survey) { survey.visible? }) + def open? return false if allow_responses.blank? return true if time_indefinite? diff --git a/decidim-surveys/app/views/decidim/surveys/admin/publish_responses/index.html.erb b/decidim-surveys/app/views/decidim/surveys/admin/publish_responses/index.html.erb index 1174423e683cb..ed3d129a2d7be 100644 --- a/decidim-surveys/app/views/decidim/surveys/admin/publish_responses/index.html.erb +++ b/decidim-surveys/app/views/decidim/surveys/admin/publish_responses/index.html.erb @@ -1,5 +1,5 @@ - <% add_decidim_page_title(t(".title")) %> +

diff --git a/decidim-surveys/app/views/decidim/surveys/admin/responses/show.html.erb b/decidim-surveys/app/views/decidim/surveys/admin/responses/show.html.erb index 8ae094744e3ac..40769f5b009e1 100644 --- a/decidim-surveys/app/views/decidim/surveys/admin/responses/show.html.erb +++ b/decidim-surveys/app/views/decidim/surveys/admin/responses/show.html.erb @@ -1,7 +1,9 @@ +<% add_decidim_page_title(t(".title", number: current_idx)) %> +

- <%= t ".title", number: current_idx %> + <%= t(".title", number: current_idx) %> <%= link_to t("actions.next", scope: "decidim.forms.admin.questionnaires.responses").html_safe, next_url, rel: "next", class: "button button__sm button__secondary next" unless last? %> <%= link_to t("actions.previous", scope: "decidim.forms.admin.questionnaires.responses").html_safe, prev_url, rel: "prev", class: "button button__sm button__secondary prev" unless first? %> diff --git a/decidim-surveys/app/views/decidim/surveys/admin/surveys/index.html.erb b/decidim-surveys/app/views/decidim/surveys/admin/surveys/index.html.erb index 308db89b9beaf..f0577ad8ff074 100644 --- a/decidim-surveys/app/views/decidim/surveys/admin/surveys/index.html.erb +++ b/decidim-surveys/app/views/decidim/surveys/admin/surveys/index.html.erb @@ -26,7 +26,7 @@ <%= link_to decidim_sanitize_translated(survey.title), edit_survey_path(survey) %>

"> - <%= survey.questionnaire.questions.not_separator.size %> + <%= survey.questionnaire.question_types.size %> "> <%= survey.questionnaire.count_participants %> diff --git a/decidim-surveys/db/data/20260314063300_reindex_surveys.rb b/decidim-surveys/db/data/20260314063300_reindex_surveys.rb new file mode 100644 index 0000000000000..50ddd02a510d5 --- /dev/null +++ b/decidim-surveys/db/data/20260314063300_reindex_surveys.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ReindexSurveys < ActiveRecord::Migration[7.2] + def up + Decidim::Component.where(manifest_name: :surveys).published.find_each do |component| + component.manifest.run_hooks(:publish, component) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/decidim-surveys/lib/decidim/surveys/component.rb b/decidim-surveys/lib/decidim/surveys/component.rb index c5a765bfd84dc..94e93dfd6999c 100644 --- a/decidim-surveys/lib/decidim/surveys/component.rb +++ b/decidim-surveys/lib/decidim/surveys/component.rb @@ -12,6 +12,18 @@ component.specific_data_importer_class_name = "Decidim::Surveys::DataImporter" component.query_type = "Decidim::Surveys::SurveysType" + component.on(:publish) do |instance| + Decidim::Surveys::Survey.where(component: instance).find_each do |result| + Decidim::UpdateSearchIndexesJob.perform_later([result]) + end + end + + component.on(:unpublish) do |instance| + Decidim::Surveys::Survey.where(component: instance).find_each do |result| + Decidim::RemoveSearchIndexesJob.perform_later([result]) + end + end + component.data_portable_entities = ["Decidim::Forms::Response"] component.newsletter_participant_entities = ["Decidim::Forms::Response"] @@ -19,6 +31,7 @@ component.register_resource(:survey) do |resource| resource.model_class_name = "Decidim::Surveys::Survey" resource.card = "decidim/surveys/survey" + resource.searchable = true resource.actions = %w(respond) end diff --git a/decidim-surveys/spec/cells/decidim/surveys/survey_card_metadata_cell_spec.rb b/decidim-surveys/spec/cells/decidim/surveys/survey_card_metadata_cell_spec.rb index edf798db0f3f0..42f56f9acf087 100644 --- a/decidim-surveys/spec/cells/decidim/surveys/survey_card_metadata_cell_spec.rb +++ b/decidim-surveys/spec/cells/decidim/surveys/survey_card_metadata_cell_spec.rb @@ -39,10 +39,16 @@ module Decidim::Surveys end describe "questions_count_item" do - it "renders the correct number of questions and survey icon" do - questions_count = survey.questionnaire.questions.size + let!(:question_separator) { create(:questionnaire_question, questionnaire: survey.questionnaire, question_type: "separator") } + let!(:question_title_desc) { create(:questionnaire_question, questionnaire: survey.questionnaire, question_type: "title_and_description") } + let!(:question_regular) { create(:questionnaire_question, questionnaire: survey.questionnaire, question_type: "short_response") } + + it "renders only the number of actual questions, excluding separators and title_and_description" do + questions_count = survey.questionnaire.question_types.size expect(subject.to_s).to include("#{questions_count} #{I18n.t("questions", scope: "decidim.surveys.surveys.show")}") expect(subject.to_s).to include("survey-line") + # 3 from the factory + 1 question_regular from this spec + expect(questions_count).to eq(4) end end end diff --git a/decidim-surveys/spec/system/admin_manages_component_publication_spec.rb b/decidim-surveys/spec/system/admin_manages_component_publication_spec.rb new file mode 100644 index 0000000000000..d462604978035 --- /dev/null +++ b/decidim-surveys/spec/system/admin_manages_component_publication_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages component publication" do + include_context "when managing a component as an admin" do + let!(:resource) { create(:survey, :published, :clean_after_publish, component:) } + + context "when cycling through publication states" do + let!(:component) { create(:surveys_component, participatory_space:) } + + include_examples "cycling through publication states" + end + + context "when component is unpublished, and admin publishes" do + let!(:component) { create(:surveys_component, :unpublished, participatory_space:) } + + include_examples "add component resources to search index" + end + + context "when component is published, and admin unpublishes" do + let!(:component) { create(:surveys_component, :published, participatory_space:) } + + include_examples "removes component resources from search index" + end + end +end diff --git a/decidim-surveys/spec/system/admin_publishes_component_spec.rb b/decidim-surveys/spec/system/admin_publishes_component_spec.rb deleted file mode 100644 index fff8d77cc2862..0000000000000 --- a/decidim-surveys/spec/system/admin_publishes_component_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "Admin publishes component" do - let(:manifest_name) { "surveys" } - let!(:resource) { create(:survey, :published, :clean_after_publish, component:) } - - include_context "when cycling through publication states" -end diff --git a/decidim-surveys/spec/system/question_ordering_spec.rb b/decidim-surveys/spec/system/question_ordering_spec.rb new file mode 100644 index 0000000000000..835216fd836b5 --- /dev/null +++ b/decidim-surveys/spec/system/question_ordering_spec.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Question ordering", "#reorder_questions" do + let(:manifest_name) { "surveys" } + let!(:component) do + create(:component, + manifest:, + participatory_space:, + published_at: nil) + end + let!(:questionnaire) { create(:questionnaire) } + let!(:survey) { create(:survey, :published, :clean_after_publish, component:, questionnaire:) } + let!(:first_question) { create(:questionnaire_question, questionnaire:, body: { en: "First question" }, position: 0) } + let!(:second_question) { create(:questionnaire_question, questionnaire:, body: { en: "Second question" }, position: 1) } + + include_context "when managing a component as an admin" + + before do + within "tr", text: decidim_sanitize_translated(survey.title) do + find("button[data-controller='dropdown']").click + click_on "Questions" + end + end + + it "shows questions in the correct order" do + expect(page).to have_content("First question #1") + expect(page).to have_content("Second question #2") + end + + it "updates positions after adding a new question", :js do + click_on "Add question" + + expect(page).to have_content("First question #1") + expect(page).to have_content("Second question #2") + expect(page).to have_content("Question #3") + end + + it "can add and save new questions with correct positions", :js do + click_on "Add question" + + expand_all_questions + + within ".questionnaire-question:last-of-type" do + fill_in find_nested_form_field_locator("body_en"), with: "Third question" + end + + click_on "Save" + expect(page).to have_callout("Survey questions successfully saved.") + + expect(page).to have_content("First question #1") + expect(page).to have_content("Second question #2") + expect(page).to have_content("Third question #3") + end + + it "allows reordering a newly added question", :js do + create_and_fill_third_question + + drag_latest_question_to_first + + ordered_headers = question_headers + expect(ordered_headers[0]).to include("Third question #1") + expect(ordered_headers[1]).to include("First question #2") + expect(ordered_headers[2]).to include("Second question #3") + end + + it "persists the reordered questions after saving", :js do + create_and_fill_third_question + + drag_latest_question_to_first + + click_on "Save" + expect(page).to have_callout("Survey questions successfully saved.") + + ordered_headers = question_headers + expect(ordered_headers[0]).to include("Third question #1") + expect(ordered_headers[1]).to include("First question #2") + expect(ordered_headers[2]).to include("Second question #3") + end + + def expand_all_questions + find(".button.expand-all").click + end + + def find_nested_form_field_locator(attribute, visible: :visible) + find_nested_form_field(attribute, visible:)["id"] + end + + def find_nested_form_field(attribute, visible: :visible) + current_scope.find(nested_form_field_selector(attribute), visible:) + end + + def nested_form_field_selector(attribute) + "[id$=#{attribute}]" + end + + def create_and_fill_third_question + click_on "Add question" + + expand_all_questions + + within ".questionnaire-question:last-of-type" do + fill_in find_nested_form_field_locator("body_en"), with: "Third question" + end + end + + def drag_latest_question_to_first + draggable_questions = all(".questionnaire-question .card-divider") + draggable_questions.last.drag_to(draggable_questions.first) + end + + def question_headers + all(".questionnaire-question .card-divider").map(&:text) + end +end diff --git a/decidim-system/app/controllers/decidim/system/admins_controller.rb b/decidim-system/app/controllers/decidim/system/admins_controller.rb index 14205f2d5a260..2e0a0d37dc5c6 100644 --- a/decidim-system/app/controllers/decidim/system/admins_controller.rb +++ b/decidim-system/app/controllers/decidim/system/admins_controller.rb @@ -24,7 +24,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("admins.create.error", scope: "decidim.system") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -46,7 +46,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("admins.update.error", scope: "decidim.system") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-system/app/controllers/decidim/system/api_users_controller.rb b/decidim-system/app/controllers/decidim/system/api_users_controller.rb index 09f2e91a9f9e5..29503fe3b352b 100644 --- a/decidim-system/app/controllers/decidim/system/api_users_controller.rb +++ b/decidim-system/app/controllers/decidim/system/api_users_controller.rb @@ -51,7 +51,7 @@ def create on(:invalid) do flash[:error] = I18n.t("api_user.create.error", scope: "decidim.system") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-system/app/controllers/decidim/system/devise/sessions_controller.rb b/decidim-system/app/controllers/decidim/system/devise/sessions_controller.rb index 8dce6f2a90958..c6221d625c535 100644 --- a/decidim-system/app/controllers/decidim/system/devise/sessions_controller.rb +++ b/decidim-system/app/controllers/decidim/system/devise/sessions_controller.rb @@ -18,7 +18,7 @@ class SessionsController < ::Devise::SessionsController def redirect_to_referer_or_path set_flash_message(:alert, "csrf_token", scope: "devise.failure") - redirect_back(fallback_location: root_path) + redirect_back_or_to(root_path) end def current_organization; end diff --git a/decidim-system/app/controllers/decidim/system/oauth_applications_controller.rb b/decidim-system/app/controllers/decidim/system/oauth_applications_controller.rb index 9796426d76f72..5a1c49d9a11d7 100644 --- a/decidim-system/app/controllers/decidim/system/oauth_applications_controller.rb +++ b/decidim-system/app/controllers/decidim/system/oauth_applications_controller.rb @@ -30,7 +30,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("oauth_applications.create.error", scope: "decidim.system") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -55,7 +55,7 @@ def update on(:invalid) do |application| @oauth_application = application flash.now[:error] = I18n.t("oauth_applications.update.error", scope: "decidim.system") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-system/app/controllers/decidim/system/organizations_controller.rb b/decidim-system/app/controllers/decidim/system/organizations_controller.rb index 4aa65546820e6..f134b37ca9e1b 100644 --- a/decidim-system/app/controllers/decidim/system/organizations_controller.rb +++ b/decidim-system/app/controllers/decidim/system/organizations_controller.rb @@ -24,12 +24,12 @@ def create on(:invalid_invitation) do flash.now[:alert] = t("organizations.create.error_invitation", scope: "decidim.system") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end on(:invalid) do flash.now[:alert] = t("organizations.create.error", scope: "decidim.system") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -55,7 +55,7 @@ def update on(:invalid) do flash.now[:alert] = I18n.t("organizations.update.error", scope: "decidim.system") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-system/app/forms/decidim/system/register_organization_form.rb b/decidim-system/app/forms/decidim/system/register_organization_form.rb index ab099af92e6a3..7208d62b5fd02 100644 --- a/decidim-system/app/forms/decidim/system/register_organization_form.rb +++ b/decidim-system/app/forms/decidim/system/register_organization_form.rb @@ -8,6 +8,7 @@ module System # class RegisterOrganizationForm < BaseOrganizationForm include JsonbAttributes + mimic :organization attribute :name, String diff --git a/decidim-system/decidim-system.gemspec b/decidim-system/decidim-system.gemspec index b6243ea637167..56752bd49daaf 100644 --- a/decidim-system/decidim-system.gemspec +++ b/decidim-system/decidim-system.gemspec @@ -31,7 +31,7 @@ Gem::Specification.new do |s| s.add_dependency "active_link_to", "~> 1.0" s.add_dependency "decidim-core", version - s.add_dependency "devise", "~> 4.7" + s.add_dependency "devise", ">= 4.7", "< 6.0" s.add_dependency "devise-i18n", "~> 1.2" s.add_dependency "devise_invitable", "~> 2.0", ">= 2.0.9" diff --git a/decidim-system/lib/decidim/system.rb b/decidim-system/lib/decidim/system.rb index 3267f8718c740..73acc7848b8a3 100644 --- a/decidim-system/lib/decidim/system.rb +++ b/decidim-system/lib/decidim/system.rb @@ -9,11 +9,15 @@ module Decidim # eye view of the whole system. # module System - include ActiveSupport::Configurable + class << self + def config = self - # The length of API secrets generated for API users. - config_accessor :api_users_secret_length do - ENV.fetch("DECIDIM_SYSTEM_API_USERS_SECRET_LENGTH", 32) + def configure + yield self + end end + + # The length of API secrets generated for API users. + mattr_accessor :api_users_secret_length, default: ENV.fetch("DECIDIM_SYSTEM_API_USERS_SECRET_LENGTH", 32).to_i end end diff --git a/decidim-system/lib/decidim/system/menu.rb b/decidim-system/lib/decidim/system/menu.rb index 2e2a2a741e0ac..abfe75e58dd95 100644 --- a/decidim-system/lib/decidim/system/menu.rb +++ b/decidim-system/lib/decidim/system/menu.rb @@ -9,7 +9,7 @@ def self.register_system_menu! I18n.t("menu.dashboard", scope: "decidim.system"), decidim_system.root_path, position: 1, - active: ["decidim/system/dashboard" => :show] + active: [{ "decidim/system/dashboard" => :show }] if Decidim.module_installed?(:api) menu.add_item :api_credentials, I18n.t("menu.api_credentials", scope: "decidim.system"), diff --git a/decidim-templates/app/controllers/decidim/templates/admin/block_user_templates_controller.rb b/decidim-templates/app/controllers/decidim/templates/admin/block_user_templates_controller.rb index ea5bddd5594d8..1c84239b0e214 100644 --- a/decidim-templates/app/controllers/decidim/templates/admin/block_user_templates_controller.rb +++ b/decidim-templates/app/controllers/decidim/templates/admin/block_user_templates_controller.rb @@ -62,7 +62,7 @@ def update on(:invalid) do |template| @template = template flash.now[:error] = I18n.t("templates.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end @@ -85,7 +85,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("templates.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end diff --git a/decidim-templates/app/controllers/decidim/templates/admin/proposal_answer_templates_controller.rb b/decidim-templates/app/controllers/decidim/templates/admin/proposal_answer_templates_controller.rb index 14142af09c720..847c01826740f 100644 --- a/decidim-templates/app/controllers/decidim/templates/admin/proposal_answer_templates_controller.rb +++ b/decidim-templates/app/controllers/decidim/templates/admin/proposal_answer_templates_controller.rb @@ -39,7 +39,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("templates.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -58,7 +58,7 @@ def destroy def fetch enforce_permission_to(:read, :template, template:, proposal:) - return render json: { msg: I18n.t("templates.fetch.error", scope: "decidim.admin") }, status: :unprocessable_entity if template.blank? + return render json: { msg: I18n.t("templates.fetch.error", scope: "decidim.admin") }, status: :unprocessable_content if template.blank? state = fetch_proposal_state(template) @@ -86,7 +86,7 @@ def update on(:invalid) do |template| @template = template flash.now[:error] = I18n.t("templates.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-templates/app/controllers/decidim/templates/admin/questionnaire_templates_controller.rb b/decidim-templates/app/controllers/decidim/templates/admin/questionnaire_templates_controller.rb index 4fb6338131ed7..5dd3ad766fc88 100644 --- a/decidim-templates/app/controllers/decidim/templates/admin/questionnaire_templates_controller.rb +++ b/decidim-templates/app/controllers/decidim/templates/admin/questionnaire_templates_controller.rb @@ -8,6 +8,7 @@ module Admin class QuestionnaireTemplatesController < Decidim::Templates::Admin::ApplicationController include Decidim::TranslatableAttributes include Decidim::Forms::Admin::Concerns::HasQuestionnaire + helper Decidim::Forms::Admin::ApplicationHelper helper_method :template, :questionnaire @@ -48,7 +49,7 @@ def create on(:invalid) do flash.now[:alert] = I18n.t("templates.create.error", scope: "decidim.admin") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -87,7 +88,7 @@ def update on(:invalid) do |template| @template = template flash.now[:error] = I18n.t("templates.update.error", scope: "decidim.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/concerns/decidim/verifications/renewable.rb b/decidim-verifications/app/controllers/concerns/decidim/verifications/renewable.rb index 9a30d62aa03e5..ac840e2cbaf1a 100644 --- a/decidim-verifications/app/controllers/concerns/decidim/verifications/renewable.rb +++ b/decidim-verifications/app/controllers/concerns/decidim/verifications/renewable.rb @@ -7,6 +7,7 @@ module Verifications # Common logic to renew authorizations module Renewable extend ActiveSupport::Concern + included do def renew enforce_permission_to(:renew, :authorization, authorization:) diff --git a/decidim-verifications/app/controllers/decidim/verifications/application_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/application_controller.rb index 535b7a5c6db08..e1c4426903e42 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/application_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/application_controller.rb @@ -27,9 +27,8 @@ def renew def confirmed_user return true if !current_user || (current_user && current_user.verifiable?) - redirect_back( - fallback_location: root_path, - alert: t( + redirect_back_or_to( + root_path, alert: t( "authorizations.create.unconfirmed", scope: "decidim.verifications" ) diff --git a/decidim-verifications/app/controllers/decidim/verifications/authorizations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/authorizations_controller.rb index 4992600476ba7..84dab0ac6b212 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/authorizations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/authorizations_controller.rb @@ -14,6 +14,7 @@ class AuthorizationsController < Verifications::ApplicationController include Decidim::UserProfile include Decidim::HtmlSafeFlash include Decidim::Verifications::Renewable + helper Decidim::DecidimFormHelper helper Decidim::AuthorizationFormHelper helper Decidim::TranslationsHelper @@ -25,7 +26,7 @@ def new; end def index; end def onboarding_pending - return redirect_back(fallback_location: authorizations_path) unless onboarding_manager.valid? + return redirect_back_or_to(authorizations_path) unless onboarding_manager.valid? authorizations = action_authorized_to(onboarding_manager.action, **onboarding_manager.action_authorized_resources) @@ -86,7 +87,7 @@ def create on(:invalid) do flash[:alert] = t("authorizations.create.error", scope: "decidim.verifications") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/csv_census/admin/census_records_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/csv_census/admin/census_records_controller.rb index 716446f38853d..ac21eb318118e 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/csv_census/admin/census_records_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/csv_census/admin/census_records_controller.rb @@ -22,7 +22,7 @@ def create_record end on(:invalid) do - render :new_record, status: :unprocessable_entity + render :new_record, status: :unprocessable_content end end end @@ -42,7 +42,7 @@ def update_record on(:invalid) do flash.now[:alert] = I18n.t("census_records.update_record.invalid", scope: "decidim.verifications.csv_census.admin") - render action: "edit_record", status: :unprocessable_entity + render action: "edit_record", status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb index 97cb23da6d3b2..ebb938b7f0a23 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb @@ -33,7 +33,7 @@ def update on(:invalid) do flash.now[:alert] = t("config.update.error", scope: "decidim.verifications.id_documents.admin") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/confirmations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/confirmations_controller.rb index 894a454295084..368efe41a4739 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/confirmations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/confirmations_controller.rb @@ -35,7 +35,7 @@ def create on(:invalid) do flash.now[:alert] = t("confirmations.create.error", scope: "decidim.verifications.id_documents.admin") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb index 0f30ab3f6d7ff..bd1a2168f5d25 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb @@ -33,7 +33,7 @@ def create on(:invalid) do flash.now[:alert] = t("offline_confirmations.create.error", scope: "decidim.verifications.id_documents.admin") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb index ed999cb8fb90e..4a83d7761a6c3 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb @@ -42,7 +42,7 @@ def create on(:invalid) do flash.now[:alert] = t("authorizations.create.error", scope: "decidim.verifications.id_documents") - render action: :new, status: :unprocessable_entity + render action: :new, status: :unprocessable_content end end end @@ -72,7 +72,7 @@ def update on(:invalid) do flash.now[:alert] = t("authorizations.update.error", scope: "decidim.verifications.id_documents") - render action: :edit, status: :unprocessable_entity + render action: :edit, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/postal_letter/admin/postages_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/postal_letter/admin/postages_controller.rb index fa6ce6ef76d09..e517c3ae27b11 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/postal_letter/admin/postages_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/postal_letter/admin/postages_controller.rb @@ -28,7 +28,7 @@ def create end on(:invalid) do - render json: { error: I18n.t("postages.create.error", scope: "decidim.verifications.postal_letter.admin") }, status: :unprocessable_entity + render json: { error: I18n.t("postages.create.error", scope: "decidim.verifications.postal_letter.admin") }, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/postal_letter/authorizations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/postal_letter/authorizations_controller.rb index bc7eab63253eb..4b9a3403cab15 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/postal_letter/authorizations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/postal_letter/authorizations_controller.rb @@ -29,7 +29,7 @@ def create on(:invalid) do flash.now[:alert] = t("authorizations.create.error", scope: "decidim.verifications.postal_letter") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -53,7 +53,7 @@ def update on(:invalid) do flash.now[:alert] = t("authorizations.update.error", scope: "decidim.verifications.postal_letter") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/controllers/decidim/verifications/sms/authorizations_controller.rb b/decidim-verifications/app/controllers/decidim/verifications/sms/authorizations_controller.rb index ece8cb3cc392e..d25a861df897b 100644 --- a/decidim-verifications/app/controllers/decidim/verifications/sms/authorizations_controller.rb +++ b/decidim-verifications/app/controllers/decidim/verifications/sms/authorizations_controller.rb @@ -27,7 +27,7 @@ def create end on(:invalid) do flash.now[:alert] = t("authorizations.create.error", scope: "decidim.verifications.sms") - render :new, status: :unprocessable_entity + render :new, status: :unprocessable_content end end end @@ -52,7 +52,7 @@ def update on(:invalid) do flash.now[:alert] = t("authorizations.update.error", scope: "decidim.verifications.sms") - render :edit, status: :unprocessable_entity + render :edit, status: :unprocessable_content end end end diff --git a/decidim-verifications/app/forms/decidim/verifications/csv_census/admin/census_data_form.rb b/decidim-verifications/app/forms/decidim/verifications/csv_census/admin/census_data_form.rb index ce5fc4e0149e2..a84c16a5b99a9 100644 --- a/decidim-verifications/app/forms/decidim/verifications/csv_census/admin/census_data_form.rb +++ b/decidim-verifications/app/forms/decidim/verifications/csv_census/admin/census_data_form.rb @@ -8,6 +8,7 @@ module Admin class CensusDataForm < Form include Decidim::HasUploadValidations include Decidim::ProcessesFileLocally + mimic :census_data attribute :file, Decidim::Attributes::Blob diff --git a/decidim-verifications/app/forms/decidim/verifications/id_documents/admin/config_form.rb b/decidim-verifications/app/forms/decidim/verifications/id_documents/admin/config_form.rb index ca7650af33a42..61676037af721 100644 --- a/decidim-verifications/app/forms/decidim/verifications/id_documents/admin/config_form.rb +++ b/decidim-verifications/app/forms/decidim/verifications/id_documents/admin/config_form.rb @@ -7,6 +7,7 @@ module IdDocuments module Admin class ConfigForm < Decidim::Form include TranslatableAttributes + mimic :config attribute :offline, Boolean diff --git a/decidim-verifications/app/views/decidim/verifications/csv_census/admin/census/index.html.erb b/decidim-verifications/app/views/decidim/verifications/csv_census/admin/census/index.html.erb index f589873d26043..e8ebfacf58b16 100644 --- a/decidim-verifications/app/views/decidim/verifications/csv_census/admin/census/index.html.erb +++ b/decidim-verifications/app/views/decidim/verifications/csv_census/admin/census/index.html.erb @@ -1,9 +1,9 @@ -<% add_decidim_page_title(t("admin.index.title", scope: "decidim.verifications.csv_census")) %> +<% add_decidim_page_title(t(".title")) %>

- <%= t("index.title", scope: "decidim.verifications.csv_census.admin") %> + <%= t(".title") %> <%= link_to t("index.import_csv", scope: "decidim.verifications.csv_census.admin"), new_import_census_logs_path, method: :get, class: "button button__sm button__transparent-secondary" %>