diff --git a/.github/workflows/ci_ai.yml b/.github/workflows/ci_ai.yml index 84ed4b7..a003c06 100644 --- a/.github/workflows/ci_ai.yml +++ b/.github/workflows/ci_ai.yml @@ -6,14 +6,15 @@ on: - main - release/* - "*-stable" + - "*bump*" pull_request: branches-ignore: - "chore/l10n*" env: CI: "true" - RUBY_VERSION: 3.2.2 - NODE_VERSION: 18.17.1 + RUBY_VERSION: 3.3.4 + NODE_VERSION: 22.16.0 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -69,6 +70,10 @@ jobs: npm- - run: bundle exec rake test_app name: Create test app + - run: | + rm -f ./spec/decidim_dummy_app/app/services/dummy_signature_handler.rb + rm -f ./spec/decidim_dummy_app/app/services/dummy_sms_mobile_phone_validator.rb + name: Remove Initiative-dependent dummy files - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots name: Create the screenshots folder - uses: nanasess/setup-chromedriver@v2 diff --git a/.github/workflows/ci_lint.yml b/.github/workflows/ci_lint.yml index d1505a9..9791a2a 100644 --- a/.github/workflows/ci_lint.yml +++ b/.github/workflows/ci_lint.yml @@ -4,11 +4,12 @@ on: push: branches: - main + - "*bump*" pull_request: env: - RUBY_VERSION: 3.2.2 - NODE_VERSION: 18.17.1 + RUBY_VERSION: 3.3.4 + NODE_VERSION: 22.16.0 jobs: lint-report: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0f99bad..26c7e0a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -76,4 +76,4 @@ rubycritic: test stable: extends: .test variables: - DECIDIM_VERSION: "~> 0.29.0" + DECIDIM_VERSION: "~> 0.31.0" diff --git a/.node-version b/.node-version index 4a1f488..adb5558 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -18.17.1 +22.14.0 \ No newline at end of file diff --git a/.ruby-version b/.ruby-version index be94e6f..2c6109e 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.2 +3.3.4 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 41f1bd3..329d164 100644 --- a/Gemfile +++ b/Gemfile @@ -6,12 +6,12 @@ ruby RUBY_VERSION gem "concurrent-ruby", "= 1.3.4" -gem "decidim", "~> 0.29" +gem "decidim", "~> 0.31" gem "decidim-ai", path: "." -gem "decidim-debates", "~> 0.29" -gem "decidim-initiatives", "~> 0.29" -gem "decidim-meetings", "~> 0.29" -gem "decidim-proposals", "~> 0.29" +gem "decidim-debates", "~> 0.31" +gem "decidim-initiatives", "~> 0.31" +gem "decidim-meetings", "~> 0.31" +gem "decidim-proposals", "~> 0.31" gem "bootsnap", "~> 1.4" gem "puma", ">= 6.3" @@ -21,7 +21,7 @@ group :development, :test do gem "faker" - gem "decidim-dev", "~> 0.29" + gem "decidim-dev", "~> 0.31" gem "rubocop-performance" gem "simplecov", require: false diff --git a/Gemfile.lock b/Gemfile.lock index 86b55a7..d518573 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,81 +1,89 @@ PATH remote: . specs: - decidim-ai (0.29.2) + decidim-ai (0.31.0) classifier-reborn (~> 2.3.0) - decidim-core (~> 0.29.0) + decidim-core (~> 0.31.0) GEM remote: https://rubygems.org/ specs: - actioncable (7.0.8.7) - actionpack (= 7.0.8.7) - activesupport (= 7.0.8.7) + actioncable (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.7) - actionpack (= 7.0.8.7) - activejob (= 7.0.8.7) - activerecord (= 7.0.8.7) - activestorage (= 7.0.8.7) - activesupport (= 7.0.8.7) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.8.7) - actionpack (= 7.0.8.7) - actionview (= 7.0.8.7) - activejob (= 7.0.8.7) - activesupport (= 7.0.8.7) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.8.7) - actionview (= 7.0.8.7) - activesupport (= 7.0.8.7) - rack (~> 2.0, >= 2.2.4) + 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) + mail (>= 2.8.0) + actionmailer (7.2.3) + actionpack (= 7.2.3) + actionview (= 7.2.3) + activejob (= 7.2.3) + activesupport (= 7.2.3) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (7.2.3) + actionview (= 7.2.3) + activesupport (= 7.2.3) + cgi + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4, < 3.3) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.7) - actionpack (= 7.0.8.7) - activerecord (= 7.0.8.7) - activestorage (= 7.0.8.7) - activesupport (= 7.0.8.7) + 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) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.7) - activesupport (= 7.0.8.7) + actionview (7.2.3) + activesupport (= 7.2.3) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) + cgi + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) active_link_to (1.0.5) actionpack addressable - activejob (7.0.8.7) - activesupport (= 7.0.8.7) + activejob (7.2.3) + activesupport (= 7.2.3) globalid (>= 0.3.6) - activemodel (7.0.8.7) - activesupport (= 7.0.8.7) - activerecord (7.0.8.7) - activemodel (= 7.0.8.7) - activesupport (= 7.0.8.7) - activestorage (7.0.8.7) - actionpack (= 7.0.8.7) - activejob (= 7.0.8.7) - activerecord (= 7.0.8.7) - activesupport (= 7.0.8.7) + activemodel (7.2.3) + activesupport (= 7.2.3) + activerecord (7.2.3) + activemodel (= 7.2.3) + activesupport (= 7.2.3) + timeout (>= 0.4.0) + activestorage (7.2.3) + actionpack (= 7.2.3) + activejob (= 7.2.3) + activerecord (= 7.2.3) + activesupport (= 7.2.3) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.8.7) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (7.2.3) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) acts_as_list (1.2.4) activerecord (>= 6.1) activesupport (>= 6.1) @@ -83,11 +91,12 @@ GEM public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) base64 (0.2.0) - batch-loader (1.5.0) + batch-loader (2.0.6) bcrypt (3.1.20) - better_html (2.1.1) - actionview (>= 6.0) - activesupport (>= 6.0) + benchmark (0.5.0) + better_html (2.2.0) + actionview (>= 7.0) + activesupport (>= 7.0) ast (~> 2.0) erubi (~> 1.4) parser (>= 2.4) @@ -96,9 +105,9 @@ GEM bindex (0.8.1) bootsnap (1.18.4) msgpack (~> 1.2) - browser (2.7.1) + browser (6.2.0) builder (3.3.0) - bullet (7.1.6) + bullet (8.0.8) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) byebug (11.1.3) @@ -122,139 +131,155 @@ 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) childprocess (5.1.0) logger (~> 1.5) + chunky_png (1.4.0) classifier-reborn (2.3.0) fast-stemmer (~> 1.0) matrix (~> 0.4) cmdparse (3.0.7) - commonmarker (0.23.11) + commonmarker (0.23.12) concurrent-ruby (1.3.4) - crack (1.0.0) + connection_pool (2.5.5) + crack (1.0.1) bigdecimal rexml crass (1.0.6) css_parser (1.21.0) addressable csv (3.3.2) - dartsass (1.49.8) + data_migrate (11.3.1) + activerecord (>= 6.1) + railties (>= 6.1) date (3.4.1) date_validator (0.12.0) activemodel (>= 3) activesupport (>= 3) - decidim (0.29.2) - decidim-accountability (= 0.29.2) - decidim-admin (= 0.29.2) - decidim-api (= 0.29.2) - decidim-assemblies (= 0.29.2) - decidim-blogs (= 0.29.2) - decidim-budgets (= 0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-debates (= 0.29.2) - decidim-forms (= 0.29.2) - decidim-generators (= 0.29.2) - decidim-meetings (= 0.29.2) - decidim-pages (= 0.29.2) - decidim-participatory_processes (= 0.29.2) - decidim-proposals (= 0.29.2) - decidim-sortitions (= 0.29.2) - decidim-surveys (= 0.29.2) - decidim-system (= 0.29.2) - decidim-verifications (= 0.29.2) - decidim-accountability (0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-admin (0.29.2) + decidim (0.31.1) + decidim-accountability (= 0.31.1) + decidim-admin (= 0.31.1) + decidim-api (= 0.31.1) + decidim-assemblies (= 0.31.1) + decidim-blogs (= 0.31.1) + decidim-budgets (= 0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-debates (= 0.31.1) + decidim-forms (= 0.31.1) + decidim-generators (= 0.31.1) + decidim-meetings (= 0.31.1) + decidim-pages (= 0.31.1) + decidim-participatory_processes (= 0.31.1) + decidim-proposals (= 0.31.1) + decidim-sortitions (= 0.31.1) + decidim-surveys (= 0.31.1) + decidim-system (= 0.31.1) + decidim-verifications (= 0.31.1) + decidim-accountability (0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-admin (0.31.1) active_link_to (~> 1.0) - decidim-core (= 0.29.2) + decidim-core (= 0.31.1) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-api (0.29.2) - decidim-core (= 0.29.2) - graphql (~> 2.2.6) - graphql-docs (~> 4.0) + decidim-api (0.31.1) + decidim-core (= 0.31.1) + devise-jwt (~> 0.12.1) + graphql (~> 2.4.0, >= 2.4.17) + graphql-docs (~> 5.0) rack-cors (~> 1.0) - decidim-assemblies (0.29.2) - decidim-core (= 0.29.2) - decidim-blogs (0.29.2) - decidim-admin (= 0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-budgets (0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-comments (0.29.2) - decidim-core (= 0.29.2) + decidim-assemblies (0.31.1) + decidim-core (= 0.31.1) + decidim-blogs (0.31.1) + decidim-admin (= 0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-budgets (0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-comments (0.31.1) + decidim-core (= 0.31.1) redcarpet (~> 3.5, >= 3.5.1) - decidim-core (0.29.2) + decidim-core (0.31.1) active_link_to (~> 1.0) acts_as_list (~> 1.0) - batch-loader (~> 1.2) - browser (~> 2.7) + batch-loader (~> 2.0) + browser (~> 6.2.0) cells-erb (~> 0.1.0) cells-rails (~> 0.1.3) charlock_holmes (~> 0.7) - concurrent-ruby (= 1.3.4) + chartkick (~> 5.1.2) + concurrent-ruby (~> 1.3.0) + connection_pool (< 3) + data_migrate (~> 11.3) date_validator (~> 0.12.0) devise (~> 4.7) - devise-i18n (~> 1.2, < 1.11.1) + devise-i18n (~> 1.2) diffy (~> 3.3) doorkeeper (~> 5.6, >= 5.6.6) doorkeeper-i18n (~> 4.0) file_validators (~> 3.0) fog-local (~> 0.6) - foundation_rails_helper (~> 4.0) geocoder (~> 1.8) hashdiff (>= 0.4.0, < 2.0.0) + hexapdf (~> 1.1.0) image_processing (~> 1.2) invisible_captcha (~> 0.12) kaminari (~> 1.2, >= 1.2.1) loofah (~> 2.19, >= 2.19.1) mime-types (>= 1.16, < 4.0) mini_magick (~> 4.9) - net-smtp (~> 0.3.1) + net-smtp (~> 0.5.0) nokogiri (~> 1.16, >= 1.16.2) omniauth (~> 2.0) omniauth-facebook (~> 5.0) omniauth-google-oauth2 (~> 1.0) omniauth-rails_csrf_protection (~> 1.0) omniauth-twitter (~> 1.4) - paper_trail (~> 12.0) - pg (~> 1.4.0, < 2) + paper_trail (~> 16.0) + paranoia (~> 3.0.0) + pg (~> 1.5.0, < 2) pg_search (~> 2.2) premailer-rails (~> 1.10) - psych (~> 4.0) rack (~> 2.2, >= 2.2.8.1) rack-attack (~> 6.0) - rails (~> 7.0.8) + rails (~> 7.2.0, >= 7.2.2.2) rails-i18n (~> 7.0) - ransack (~> 3.2.1) + ransack (~> 4.2.0) redis (~> 4.1) - request_store (~> 1.5.0) + request_store (~> 1.7.0) + rqrcode (~> 2.2.0) rubyXL (~> 3.4) rubyzip (~> 2.0) - shakapacker (~> 7.1.0) - valid_email2 (~> 4.0) + shakapacker (~> 8.3.0) + valid_email2 (~> 7.0) web-push (~> 3.0) - wisper (~> 2.0) - decidim-debates (0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-dev (0.29.2) - bullet (~> 7.1.6) + wisper (~> 3.0) + decidim-debates (0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-dev (0.31.1) + bullet (~> 8.0.0) byebug (~> 11.0) capybara (~> 3.39) - decidim (= 0.29.2) - erb_lint (~> 0.4.0) + decidim-admin (= 0.31.1) + decidim-api (= 0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-generators (= 0.31.1) + decidim-verifications (= 0.31.1) + erb_lint (~> 0.8.0) factory_bot_rails (~> 6.2) faker (~> 3.2) i18n-tasks (~> 1.0) nokogiri (~> 1.16, >= 1.16.2) parallel_tests (~> 4.2) - puma (~> 6.2, >= 6.3.1) + puma (~> 6.5) rails-controller-testing (~> 1.0) rspec (~> 3.12) rspec-cells (~> 0.3.7) @@ -262,15 +287,16 @@ GEM rspec-rails (~> 6.0) rspec-retry (~> 0.6.2) rspec_junit_formatter (~> 0.6.0) - rubocop (~> 1.65.0) - rubocop-capybara (~> 2.21) - rubocop-factory_bot (~> 2.26) - rubocop-faker (~> 1.1) - rubocop-performance (~> 1.21) - rubocop-rails (~> 2.25) - rubocop-rspec (~> 3.0) - rubocop-rspec_rails (~> 2.30) - rubocop-rubycw (~> 0.1) + rubocop (~> 1.78.0) + rubocop-capybara (~> 2.22.0, >= 2.22.1) + rubocop-factory_bot (~> 2.27.0) + 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-rspec (~> 3.0, >= 3.6.0) + rubocop-rspec_rails (~> 2.31.0) + rubocop-rubycw (~> 0.2.0) selenium-webdriver (~> 4.9) simplecov (~> 0.22.0) simplecov-cobertura (~> 2.1.0) @@ -279,47 +305,44 @@ GEM w3c_rspec_validators (~> 0.3.0) webmock (~> 3.18) wisper-rspec (~> 1.0) - decidim-forms (0.29.2) - decidim-core (= 0.29.2) - wicked_pdf (~> 2.1) - decidim-generators (0.29.2) - decidim-core (= 0.29.2) - decidim-initiatives (0.29.2) - decidim-admin (= 0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-verifications (= 0.29.2) - hexapdf (~> 0.32.0) - wicked_pdf (~> 2.1) - decidim-meetings (0.29.2) - decidim-core (= 0.29.2) - decidim-forms (= 0.29.2) + decidim-forms (0.31.1) + decidim-core (= 0.31.1) + decidim-generators (0.31.1) + decidim-core (= 0.31.1) + decidim-initiatives (0.31.1) + decidim-admin (= 0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-verifications (= 0.31.1) + decidim-meetings (0.31.1) + decidim-core (= 0.31.1) + decidim-forms (= 0.31.1) icalendar (~> 2.5) - decidim-pages (0.29.2) - decidim-core (= 0.29.2) - decidim-participatory_processes (0.29.2) - decidim-core (= 0.29.2) - decidim-proposals (0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - doc2text (~> 0.4.7) + decidim-pages (0.31.1) + decidim-core (= 0.31.1) + decidim-participatory_processes (0.31.1) + decidim-core (= 0.31.1) + decidim-proposals (0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + doc2text (~> 0.4.0, >= 0.4.8) redcarpet (~> 3.5, >= 3.5.1) - decidim-sortitions (0.29.2) - decidim-admin (= 0.29.2) - decidim-comments (= 0.29.2) - decidim-core (= 0.29.2) - decidim-proposals (= 0.29.2) - decidim-surveys (0.29.2) - decidim-core (= 0.29.2) - decidim-forms (= 0.29.2) - decidim-system (0.29.2) + decidim-sortitions (0.31.1) + decidim-admin (= 0.31.1) + decidim-comments (= 0.31.1) + decidim-core (= 0.31.1) + decidim-proposals (= 0.31.1) + decidim-surveys (0.31.1) + decidim-core (= 0.31.1) + decidim-forms (= 0.31.1) + decidim-system (0.31.1) active_link_to (~> 1.0) - decidim-core (= 0.29.2) + decidim-core (= 0.31.1) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-verifications (0.29.2) - decidim-core (= 0.29.2) + decidim-verifications (0.31.1) + decidim-core (= 0.31.1) declarative-builder (0.2.0) trailblazer-option (~> 0.1.0) declarative-option (0.1.0) @@ -331,24 +354,39 @@ GEM warden (~> 1.2.3) devise-i18n (1.11.0) devise (>= 4.9.0) - devise_invitable (2.0.9) + devise-jwt (0.12.1) + devise (~> 4.0) + warden-jwt_auth (~> 0.10) + devise_invitable (2.0.11) actionmailer (>= 5.0) devise (>= 4.6) - diff-lcs (1.6.0) + diff-lcs (1.6.2) diffy (3.4.3) - doc2text (0.4.7) - nokogiri (>= 1.13.2, < 1.17.0) + doc2text (0.4.8) + nokogiri (>= 1.18.2) rubyzip (~> 2.3.0) docile (1.4.1) doorkeeper (5.8.1) railties (>= 5) doorkeeper-i18n (4.0.1) - erb_lint (0.4.0) + drb (2.2.3) + dry-auto_inject (1.1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-core (1.2.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + erb (6.0.1) + erb_lint (0.8.0) activesupport better_html (>= 2.0.1) parser (>= 2.7.1.4) rainbow - rubocop + rubocop (>= 1) smart_properties erbse (0.1.4) temple @@ -357,11 +395,11 @@ GEM excon (1.2.3) extended-markdown-filter (0.7.0) html-pipeline (~> 2.9) - factory_bot (6.5.1) + 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) + railties (>= 6.1.0) faker (3.5.1) i18n (>= 1.8.11, < 2) faraday (2.12.2) @@ -373,6 +411,7 @@ GEM fast-stemmer (1.0.2) ffi (1.17.1-arm64-darwin) ffi (1.17.1-x86_64-linux-gnu) + fiber-storage (1.0.1) file_validators (3.0.0) activemodel (>= 3.2) mime-types (>= 1.0) @@ -384,11 +423,6 @@ GEM fog-local (0.8.0) fog-core (>= 1.27, < 3.0) formatador (1.1.0) - foundation_rails_helper (4.0.1) - actionpack (>= 4.1, < 7.1) - activemodel (>= 4.1, < 7.1) - activesupport (>= 4.1, < 7.1) - railties (>= 4.1, < 7.1) gemoji (3.0.1) geocoder (1.8.5) base64 (>= 0.1.0) @@ -396,22 +430,33 @@ GEM geom2d (0.4.1) globalid (1.2.1) activesupport (>= 6.1) - graphql (2.2.16) + google-protobuf (4.33.4-arm64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.33.4-x86_64-linux-gnu) + bigdecimal + rake (>= 13) + graphql (2.4.17) base64 - graphql-docs (4.0.0) + fiber-storage + logger + graphql-docs (5.2.0) commonmarker (~> 0.23, >= 0.23.6) - dartsass (~> 1.49) escape_utils (~> 1.2) extended-markdown-filter (~> 0.4) gemoji (~> 3.0) graphql (~> 2.0) html-pipeline (~> 2.14, >= 2.14.3) + logger (~> 1.6) + ostruct (~> 0.6) + sass-embedded (~> 1.58) hashdiff (1.1.2) hashie (5.0.0) - hexapdf (0.32.2) + hexapdf (1.1.1) cmdparse (~> 3.0, >= 3.0.3) - geom2d (~> 0.3) + geom2d (~> 0.4, >= 0.4.1) openssl (>= 2.2.1) + strscan (>= 3.1.2) highline (3.1.2) reline html-pipeline (2.14.3) @@ -420,18 +465,22 @@ GEM htmlentities (4.3.4) i18n (1.14.7) concurrent-ruby (~> 1.0) - i18n-tasks (1.0.14) + 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) @@ -439,7 +488,11 @@ GEM ruby-vips (>= 2.0.17, < 3) invisible_captcha (0.13.0) rails (>= 3.2.0) - io-console (0.8.0) + io-console (0.8.2) + irb (1.16.0) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) json (2.10.1) jwt (2.10.1) base64 @@ -467,6 +520,7 @@ GEM letter_opener (~> 1.7) railties (>= 5.2) rexml + lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -481,7 +535,6 @@ GEM net-smtp marcel (1.0.4) matrix (0.4.2) - method_source (1.1.0) mime-types (3.6.0) logger mime-types-data (~> 3.2015) @@ -501,12 +554,12 @@ GEM net-protocol net-protocol (0.2.2) timeout - net-smtp (0.3.4) + net-smtp (0.5.1) net-protocol nio4r (2.7.4) - nokogiri (1.16.8-arm64-darwin) + nokogiri (1.19.0-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.8-x86_64-linux) + nokogiri (1.19.0-x86_64-linux-gnu) racc (~> 1.4) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) @@ -547,20 +600,25 @@ GEM rack openssl (3.3.0) orm_adapter (0.5.0) - ostruct (0.6.1) - paper_trail (12.3.0) - activerecord (>= 5.2) - request_store (~> 1.1) + ostruct (0.6.3) + package_json (0.2.0) + paper_trail (16.0.0) + activerecord (>= 6.1) + request_store (~> 1.4) parallel (1.26.3) - parallel_tests (4.9.0) + parallel_tests (4.10.1) parallel - parser (3.3.7.1) + paranoia (3.0.1) + activerecord (>= 6, < 8.1) + parser (3.3.10.1) ast (~> 2.4.1) racc - pg (1.4.6) + pg (1.5.9) pg_search (2.3.7) activerecord (>= 6.1) activesupport (>= 6.1) + pp (0.6.3) + prettyprint premailer (1.27.0) addressable css_parser (>= 1.19.0) @@ -569,6 +627,8 @@ GEM actionmailer (>= 3) net-smtp premailer (~> 1.7, >= 1.7.9) + prettyprint (0.2.0) + prism (1.9.0) psych (4.0.6) stringio public_suffix (6.0.1) @@ -585,22 +645,27 @@ GEM rack (~> 2.2, >= 2.2.4) rack-proxy (0.7.7) rack + rack-session (1.0.2) + rack (< 3) rack-test (2.2.0) rack (>= 1.3) - rails (7.0.8.7) - actioncable (= 7.0.8.7) - actionmailbox (= 7.0.8.7) - actionmailer (= 7.0.8.7) - actionpack (= 7.0.8.7) - actiontext (= 7.0.8.7) - actionview (= 7.0.8.7) - activejob (= 7.0.8.7) - activemodel (= 7.0.8.7) - activerecord (= 7.0.8.7) - activestorage (= 7.0.8.7) - activesupport (= 7.0.8.7) + rackup (1.0.1) + rack (< 3) + webrick + 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) bundler (>= 1.15.0) - railties (= 7.0.8.7) + railties (= 7.2.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -615,49 +680,60 @@ GEM rails-i18n (7.0.10) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.0.8.7) - actionpack (= 7.0.8.7) - activesupport (= 7.0.8.7) - method_source + railties (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) + cgi + irb (~> 1.13) + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) - ransack (3.2.1) + ransack (4.2.1) activerecord (>= 6.1.5) activesupport (>= 6.1.5) i18n rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - redcarpet (3.6.0) + rdoc (7.1.0) + erb + psych (>= 4.0.0) + tsort + redcarpet (3.6.1) redis (4.8.1) regexp_parser (2.10.0) - reline (0.6.0) + reline (0.6.3) io-console (~> 0.5) - request_store (1.5.1) + request_store (1.7.0) rack (>= 1.4) responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) rexml (3.4.1) - rspec (3.13.0) + rqrcode (2.2.0) + chunky_png (~> 1.0) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.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.3) + rspec-core (3.13.6) rspec-support (~> 3.13.0) - rspec-expectations (3.13.3) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-html-matchers (0.10.0) nokogiri (~> 1) rspec (>= 3.0.0.a) - rspec-mocks (3.13.2) + rspec-mocks (3.13.7) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (6.1.5) @@ -670,44 +746,56 @@ GEM rspec-support (~> 3.13) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.13.2) + rspec-support (3.13.7) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.65.1) + rubocop (1.78.0) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.45.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.38.0) - parser (>= 3.3.1.0) - rubocop-capybara (2.21.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.26.1) - rubocop (~> 1.61) - rubocop-faker (1.2.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-capybara (2.22.1) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-factory_bot (2.27.1) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-faker (1.3.0) faker (>= 2.12.0) - rubocop (>= 1.13.0) - rubocop-performance (1.23.1) - rubocop (>= 1.48.1, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.29.0) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + rubocop-graphql (1.5.6) + lint_roller (~> 1.1) + rubocop (>= 1.72.1, < 2) + rubocop-performance (1.26.1) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rails (2.32.0) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.52.0, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.4.0) - rubocop (~> 1.61) - rubocop-rspec_rails (2.30.0) - rubocop (~> 1.61) - rubocop-rspec (~> 3, >= 3.0.1) - rubocop-rubycw (0.1.6) - rubocop (~> 1.0) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rspec (3.7.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rspec_rails (2.31.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) ruby-progressbar (1.13.0) ruby-vips (2.2.3) ffi (~> 1.12) @@ -716,15 +804,21 @@ GEM nokogiri (>= 1.10.8) rubyzip (>= 1.3.0) rubyzip (2.3.2) - selenium-webdriver (4.28.0) + 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.40.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) semantic_range (3.1.0) - shakapacker (7.1.0) + shakapacker (8.3.0) activesupport (>= 5.2) + package_json rack-proxy (>= 0.6.1) railties (>= 5.2) semantic_range (>= 2.3.0) @@ -741,11 +835,12 @@ GEM snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.2.1) + spring (4.4.2) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) stringio (3.1.3) + strscan (3.1.7) temple (0.10.3) terminal-table (4.0.0) unicode-display_width (>= 1.1.1, < 4) @@ -753,14 +848,16 @@ GEM tilt (2.6.0) timeout (0.4.3) trailblazer-option (0.1.2) + tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) unicode-display_width (2.6.0) - uniform_notifier (1.16.0) + uniform_notifier (1.18.0) uri (1.0.2) - valid_email2 (4.0.6) - activemodel (>= 3.2) + useragent (0.16.11) + valid_email2 (7.0.13) + activemodel (>= 6.0) mail (~> 2.5) version_gem (1.1.4) w3c_rspec_validators (0.3.0) @@ -773,6 +870,11 @@ GEM rexml (~> 3.2) warden (1.2.9) rack (>= 2.0.9) + warden-jwt_auth (0.12.0) + dry-auto_inject (>= 0.8, < 2) + 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) @@ -781,19 +883,17 @@ GEM web-push (3.0.1) jwt (~> 2.0) openssl (~> 3.0) - webmock (3.25.0) + webmock (3.26.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) + webrick (1.9.2) websocket (1.2.11) websocket-driver (0.7.7) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - wicked_pdf (2.8.2) - activesupport - ostruct - wisper (2.0.1) + wisper (3.0.0) wisper-rspec (1.1.0) xpath (3.2.0) nokogiri (~> 1.8) @@ -801,19 +901,20 @@ GEM PLATFORMS arm64-darwin-22 + arm64-darwin-24 x86_64-linux-gnu DEPENDENCIES bootsnap (~> 1.4) byebug (~> 11.0) concurrent-ruby (= 1.3.4) - decidim (~> 0.29) + decidim (~> 0.31) decidim-ai! - decidim-debates (~> 0.29) - decidim-dev (~> 0.29) - decidim-initiatives (~> 0.29) - decidim-meetings (~> 0.29) - decidim-proposals (~> 0.29) + decidim-debates (~> 0.31) + decidim-dev (~> 0.31) + decidim-initiatives (~> 0.31) + decidim-meetings (~> 0.31) + decidim-proposals (~> 0.31) faker letter_opener_web (~> 2.0) listen (~> 3.1) @@ -824,7 +925,7 @@ DEPENDENCIES web-console (~> 4.2) RUBY VERSION - ruby 3.2.2p53 + ruby 3.3.4p94 BUNDLED WITH 2.5.15 diff --git a/app/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job.rb b/app/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job.rb index 90e218b..8ada3d0 100644 --- a/app/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job.rb +++ b/app/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job.rb @@ -9,6 +9,7 @@ class GenericSpamAnalyzerJob < ApplicationJob def perform(reportable, author, locale, fields) @author = author @organization = reportable.organization + overall_score = I18n.with_locale(locale) do fields.map do |field| classifier.classify(translated_attribute(reportable.send(field))) @@ -26,7 +27,15 @@ def perform(reportable, author, locale, fields) private def form - @form ||= Decidim::ReportForm.new(reason: "spam", details: classifier.classification_log).with_context(current_user: reporting_user) + @form ||= Decidim::ReportForm.new( + reason: "spam", + details: classifier.classification_log, + hide: Decidim::Ai::SpamDetection.hide_reported_resources_automatically + ).with_context( + current_user: reporting_user, + can_hide: false, + marked_as_spam: true + ) end def reporting_user diff --git a/decidim-ai.gemspec b/decidim-ai.gemspec index b582149..3ab312e 100644 --- a/decidim-ai.gemspec +++ b/decidim-ai.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| "homepage_uri" => "https://decidim.org", "source_code_uri" => "https://github.com/decidim/decidim" } - s.required_ruby_version = "~> 3.2.0" + s.required_ruby_version = "~> 3.3.4" s.name = "decidim-ai" s.summary = "A Decidim module with AI tools" @@ -26,5 +26,5 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib,vendor}/**/*", "Rakefile", "README.md"] s.add_dependency "classifier-reborn", "~> 2.3.0" - s.add_dependency "decidim-core", "~> 0.29.0" + s.add_dependency "decidim-core", "~> 0.31.0" end diff --git a/lib/decidim/ai.rb b/lib/decidim/ai.rb index 2a6f280..dbec56e 100644 --- a/lib/decidim/ai.rb +++ b/lib/decidim/ai.rb @@ -10,8 +10,6 @@ module Ai module Overrides autoload :UpdateAccount, "decidim/ai/overrides/update_account" - autoload :UpdateUserGroup, "decidim/ai/overrides/update_user_group" - autoload :CreateUserGroup, "decidim/ai/overrides/create_user_group" end include ActiveSupport::Configurable diff --git a/lib/decidim/ai/engine.rb b/lib/decidim/ai/engine.rb index 722d155..81c0cff 100644 --- a/lib/decidim/ai/engine.rb +++ b/lib/decidim/ai/engine.rb @@ -7,6 +7,12 @@ class Engine < ::Rails::Engine paths["db/migrate"] = nil + initializer "decidim_ai.data_migrate", after: "decidim_core.data_migrate" do + DataMigrate.configure do |config| + config.data_migrations_path << root.join("db/data").to_s + end + end + initializer "decidim_ai.resource_classifiers" do |_app| Decidim::Ai::SpamDetection.resource_analyzers.each do |analyzer| Decidim::Ai::SpamDetection.resource_registry.register_analyzer(**analyzer) @@ -19,24 +25,12 @@ class Engine < ::Rails::Engine end end - initializer "decidim_ai.patch_resources" do - Rails.application.config.to_prepare do - Decidim::UpdateAccount.prepend Decidim::Ai::Overrides::UpdateAccount - Decidim::UpdateUserGroup.prepend Decidim::Ai::Overrides::UpdateUserGroup - Decidim::CreateUserGroup.prepend Decidim::Ai::Overrides::CreateUserGroup - end - end - initializer "decidim_ai.events.subscribe_profile" do config.to_prepare do Decidim::EventsManager.subscribe("decidim.update_account:after") do |_event_name, data| - Decidim::Ai::SpamDetection.user_spam_analyzer_job.constantize.perform_later(data[:resource]) - end - Decidim::EventsManager.subscribe("decidim.update_user_group:after") do |_event_name, data| - Decidim::Ai::SpamDetection.user_spam_analyzer_job.constantize.perform_later(data[:resource]) - end - Decidim::EventsManager.subscribe("decidim.create_user_group:after") do |_event_name, data| - Decidim::Ai::SpamDetection.user_spam_analyzer_job.constantize.perform_later(data[:resource]) + Decidim::Ai::SpamDetection::UserSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource]) end end end @@ -44,10 +38,16 @@ class Engine < ::Rails::Engine initializer "decidim_ai.events.subscribe_comments" do config.to_prepare do ActiveSupport::Notifications.subscribe("decidim.comments.create_comment:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body]) end ActiveSupport::Notifications.subscribe("decidim.comments.update_comment:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body]) end end end @@ -55,12 +55,16 @@ class Engine < ::Rails::Engine initializer "decidim_ai.events.subscribe_meeting" do config.to_prepare do ActiveSupport::Notifications.subscribe("decidim.meetings.create_meeting:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), - [:description, :title, :location_hints, :registration_terms]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), + [:description, :title, :location_hints, :registration_terms]) end ActiveSupport::Notifications.subscribe("decidim.meetings.update_meeting:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), - [:description, :title, :location_hints, :registration_terms]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), + [:description, :title, :location_hints, :registration_terms]) end end end @@ -68,10 +72,16 @@ class Engine < ::Rails::Engine initializer "decidim_ai.events.subscribe_debate" do config.to_prepare do ActiveSupport::Notifications.subscribe("decidim.debates.create_debate:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) end ActiveSupport::Notifications.subscribe("decidim.debates.update_debate:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) end end end @@ -79,10 +89,16 @@ class Engine < ::Rails::Engine initializer "decidim_ai.events.subscribe_initiatives" do config.to_prepare do ActiveSupport::Notifications.subscribe("decidim.initiatives.create_initiative:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) end ActiveSupport::Notifications.subscribe("decidim.initiatives.update_initiative:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:description, :title]) end end end @@ -90,16 +106,28 @@ class Engine < ::Rails::Engine initializer "decidim_ai.events.subscribe_proposals" do config.to_prepare do ActiveSupport::Notifications.subscribe("decidim.proposals.create_proposal:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) end ActiveSupport::Notifications.subscribe("decidim.proposals.update_proposal:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) end ActiveSupport::Notifications.subscribe("decidim.proposals.create_collaborative_draft:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) end ActiveSupport::Notifications.subscribe("decidim.proposals.update_collaborative_draft:after") do |_event_name, data| - Decidim::Ai::SpamDetection.generic_spam_analyzer_job.constantize.perform_later(data[:resource], data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) + Decidim::Ai::SpamDetection::GenericSpamAnalyzerJob + .set(wait: Decidim::Ai::SpamDetection.spam_detection_delay) + .perform_later(data[:resource], + data.dig(:extra, :event_author), data.dig(:extra, :locale), [:body, :title]) end end end diff --git a/lib/decidim/ai/language/language.rb b/lib/decidim/ai/language/language.rb index 250e868..6e74db2 100644 --- a/lib/decidim/ai/language/language.rb +++ b/lib/decidim/ai/language/language.rb @@ -16,7 +16,7 @@ module Language # end # end config_accessor :formatter do - "Decidim::Ai::Language::Formatter" + Decidim::Env.new("DECIDIM_AI_LANGUAGE_FORMATTER", "Decidim::Ai::Language::Formatter").value end end end diff --git a/lib/decidim/ai/overrides/create_user_group.rb b/lib/decidim/ai/overrides/create_user_group.rb deleted file mode 100644 index e22413e..0000000 --- a/lib/decidim/ai/overrides/create_user_group.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Ai - module Overrides - module CreateUserGroup - def call - return broadcast(:invalid) if form.invalid? - - with_events(with_transaction: true) do - create_user_group - create_membership - end - notify_admins - - broadcast(:ok, @user_group) - end - - def event_arguments - { resource: @user_group } - end - end - end - end -end diff --git a/lib/decidim/ai/overrides/update_account.rb b/lib/decidim/ai/overrides/update_account.rb deleted file mode 100644 index c6ab7fc..0000000 --- a/lib/decidim/ai/overrides/update_account.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Ai - module Overrides - module UpdateAccount - def call - return broadcast(:invalid, @form.password) unless @form.valid? - - update_personal_data - update_avatar - update_password - - if current_user.valid? - with_events do - changes = current_user.changed - current_user.save! - send_update_summary!(changes) - end - notify_followers - broadcast(:ok, current_user.unconfirmed_email.present?) - else - [:avatar, :password].each do |key| - @form.errors.add key, current_user.errors[key] if current_user.errors.has_key? key - end - broadcast(:invalid, @form.password) - end - end - - def event_arguments - { resource: current_user } - end - end - end - end -end diff --git a/lib/decidim/ai/overrides/update_user_group.rb b/lib/decidim/ai/overrides/update_user_group.rb deleted file mode 100644 index 99d1888..0000000 --- a/lib/decidim/ai/overrides/update_user_group.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Decidim - module Ai - module Overrides - module UpdateUserGroup - def update_user_group - with_events do - super - end - end - - def event_arguments - { resource: user_group } - end - end - end - end -end diff --git a/lib/decidim/ai/spam_detection/resource/base.rb b/lib/decidim/ai/spam_detection/resource/base.rb index d9db2da..3482f15 100644 --- a/lib/decidim/ai/spam_detection/resource/base.rb +++ b/lib/decidim/ai/spam_detection/resource/base.rb @@ -40,7 +40,11 @@ def error_message(klass, method_name) end def resource_hidden?(resource) - resource.class.included_modules.include?(Decidim::Reportable) && resource.hidden? + resource.class.included_modules.include?(Decidim::Reportable) && resource.hidden? && report_reasons.include?(resource.reports&.last&.reason) + end + + def report_reasons + Decidim::Report::REASONS.excluding("parent_hidden") end def classifier diff --git a/lib/decidim/ai/spam_detection/spam_detection.rb b/lib/decidim/ai/spam_detection/spam_detection.rb index d2894fa..773d586 100644 --- a/lib/decidim/ai/spam_detection/spam_detection.rb +++ b/lib/decidim/ai/spam_detection/spam_detection.rb @@ -28,10 +28,16 @@ module Strategy autoload :Bayes, "decidim/ai/spam_detection/strategy/bayes" end + # When the engine is consistently marking spam content without errors, + # you can skip human intervention by enabling this functionality + config_accessor :hide_reported_resources_automatically do + Decidim::Env.new("DECIDIM_SPAM_HIDE_REPORTED_RESOURCES_AUTOMATICALLY", false).present? + end + # This is the email address used by the spam engine to # properly identify the user that will report users and content config_accessor :reporting_user_email do - "decidim-reporting-user@example.org" + Decidim::Env.new("DECIDIM_SPAM_REPORTING_USER", "decidim-reporting-user@example.org").value end # You can configure the spam threshold for the spam detection service. @@ -39,7 +45,13 @@ module Strategy # The default value is 0.75 # Any value below the threshold will be considered spam. config_accessor :resource_score_threshold do - 0.75 + Decidim::Env.new("DECIDIM_SPAM_DETECTION_RESOURCE_SCORE_THRESHOLD", 0.75).to_f + end + + # You can configure the spam delay for the spam detection service. + # The default value is 30 seconds + config_accessor :spam_detection_delay do + Decidim::Env.new("DECIDIM_SPAM_DETECTION_DELAY_IN_SECONDS", 30).to_i.seconds end # Registered analyzers. @@ -92,7 +104,7 @@ module Strategy # Spam detection service class. # If you want to use a different spam detection service, you can use a class service having the following contract config_accessor :resource_detection_service do - "Decidim::Ai::SpamDetection::Service" + Decidim::Env.new("DECIDIM_SPAM_DETECTION_RESOURCE_SERVICE", "Decidim::Ai::SpamDetection::Service").value end # You can configure the spam threshold for the spam detection service. @@ -100,7 +112,7 @@ module Strategy # The default value is 0.75 # Any value below the threshold will be considered spam. config_accessor :user_score_threshold do - 0.75 + Decidim::Env.new("DECIDIM_SPAM_DETECTION_USER_SCORE_THRESHOLD", 0.75).to_f end # Registered analyzers. @@ -135,21 +147,16 @@ module Strategy # This config_accessor allows the implementers to change the class being used by the classifier, # in order to change the finder method or what a hidden user really is. - # The same applies for UserGroups. config_accessor :user_models do - @user_models ||= begin - user_models = {} - - user_models["Decidim::UserGroup"] = "Decidim::Ai::SpamDetection::Resource::UserBaseEntity" - user_models["Decidim::User"] = "Decidim::Ai::SpamDetection::Resource::UserBaseEntity" - user_models - end + { + "Decidim::User" => "Decidim::Ai::SpamDetection::Resource::UserBaseEntity" + } end # Spam detection service class. # If you want to use a different spam detection service, you can use a class service having the following contract config_accessor :user_detection_service do - "Decidim::Ai::SpamDetection::Service" + Decidim::Env.new("DECIDIM_SPAM_DETECTION_USER_SERVICE", "Decidim::Ai::SpamDetection::Service").value end # User spam analyzer job class. diff --git a/lib/decidim/ai/version.rb b/lib/decidim/ai/version.rb index ab4c5a6..931362d 100644 --- a/lib/decidim/ai/version.rb +++ b/lib/decidim/ai/version.rb @@ -3,7 +3,7 @@ module Decidim module Ai def self.version - "0.29.2" + "0.31.0" end end end diff --git a/spec/event_handlers/comments/user_creates_comment_spec.rb b/spec/event_handlers/comments/user_creates_comment_spec.rb index 51b6966..0bd1624 100644 --- a/spec/event_handlers/comments/user_creates_comment_spec.rb +++ b/spec/event_handlers/comments/user_creates_comment_spec.rb @@ -8,7 +8,6 @@ "comment" => { "body" => body, "alignment" => 1, - "user_group_id" => nil, "commentable" => commentable } } diff --git a/spec/event_handlers/debates/user_creates_debate_spec.rb b/spec/event_handlers/debates/user_creates_debate_spec.rb index 2ced8a1..e7e0283 100644 --- a/spec/event_handlers/debates/user_creates_debate_spec.rb +++ b/spec/event_handlers/debates/user_creates_debate_spec.rb @@ -9,9 +9,7 @@ invalid?: false, title:, description:, - user_group_id: nil, - scope:, - category:, + taxonomizations:, add_documents: attachments, documents: [], current_user: author, diff --git a/spec/event_handlers/debates/user_updates_debate_spec.rb b/spec/event_handlers/debates/user_updates_debate_spec.rb index 8f66662..17fda6c 100644 --- a/spec/event_handlers/debates/user_updates_debate_spec.rb +++ b/spec/event_handlers/debates/user_updates_debate_spec.rb @@ -7,7 +7,7 @@ Decidim::Debates::DebateForm.from_params( title:, description:, - # taxonomizations:, + taxonomizations:, id: debate.id ).with_context( current_organization: organization, diff --git a/spec/event_handlers/meetings/user_creates_meeting_spec.rb b/spec/event_handlers/meetings/user_creates_meeting_spec.rb index a6b90f0..fc5e7cc 100644 --- a/spec/event_handlers/meetings/user_creates_meeting_spec.rb +++ b/spec/event_handlers/meetings/user_creates_meeting_spec.rb @@ -15,9 +15,7 @@ address: "address", latitude: 40.1234, longitude: 2.1234, - scope:, - category:, - user_group_id: nil, + taxonomizations:, current_user: author, current_component: component, component:, diff --git a/spec/event_handlers/meetings/user_updates_meeting_spec.rb b/spec/event_handlers/meetings/user_updates_meeting_spec.rb index 430762d..9880467 100644 --- a/spec/event_handlers/meetings/user_updates_meeting_spec.rb +++ b/spec/event_handlers/meetings/user_updates_meeting_spec.rb @@ -15,9 +15,7 @@ address: "address", latitude: 40.1234, longitude: 2.1234, - scope:, - category:, - user_group_id: nil, + taxonomizations:, current_user: author, current_component: component, current_organization: organization, diff --git a/spec/event_handlers/proposals/user_creates_collaborative_draft_spec.rb b/spec/event_handlers/proposals/user_creates_collaborative_draft_spec.rb index fc6c172..247dd89 100644 --- a/spec/event_handlers/proposals/user_creates_collaborative_draft_spec.rb +++ b/spec/event_handlers/proposals/user_creates_collaborative_draft_spec.rb @@ -11,9 +11,7 @@ has_address: false, latitude: 40.1234, longitude: 2.1234, - add_documents: nil, - user_group_id: user_group.try(:id), - suggested_hashtags: [] + add_documents: nil ).with_context( current_user: author, current_organization: organization, diff --git a/spec/event_handlers/proposals/user_creates_proposal_spec.rb b/spec/event_handlers/proposals/user_creates_proposal_spec.rb index 1231fbe..2023e1a 100644 --- a/spec/event_handlers/proposals/user_creates_proposal_spec.rb +++ b/spec/event_handlers/proposals/user_creates_proposal_spec.rb @@ -6,8 +6,7 @@ let(:form) do Decidim::Proposals::ProposalForm.from_params( title:, - body:, - user_group_id: user_group.try(:id) + body: ).with_context( current_user: author, current_organization: organization, diff --git a/spec/event_handlers/proposals/user_updates_collaborative_draft_spec.rb b/spec/event_handlers/proposals/user_updates_collaborative_draft_spec.rb index b9bf1de..563b125 100644 --- a/spec/event_handlers/proposals/user_updates_collaborative_draft_spec.rb +++ b/spec/event_handlers/proposals/user_updates_collaborative_draft_spec.rb @@ -11,9 +11,7 @@ has_address: false, latitude: 40.1234, longitude: 2.1234, - add_documents: nil, - user_group_id: user_group.try(:id), - suggested_hashtags: [] + add_documents: nil ).with_context( current_user: author, current_organization: organization, diff --git a/spec/event_handlers/proposals/user_updates_proposal_spec.rb b/spec/event_handlers/proposals/user_updates_proposal_spec.rb index fc14b47..bebbcf5 100644 --- a/spec/event_handlers/proposals/user_updates_proposal_spec.rb +++ b/spec/event_handlers/proposals/user_updates_proposal_spec.rb @@ -9,8 +9,6 @@ body:, address: nil, has_address: false, - user_group_id: user_group.try(:id), - suggested_hashtags: [], attachment: nil, photos: [], add_photos: [], diff --git a/spec/event_handlers/user/user_manages_user_group_spec.rb b/spec/event_handlers/user/user_manages_user_group_spec.rb deleted file mode 100644 index 0fc5c7a..0000000 --- a/spec/event_handlers/user/user_manages_user_group_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -describe "User manages user group", type: :system do - shared_examples "user content submitted to spam analysis" do - let(:queue_size) { 1 } - let(:compared_field) { :about } - let(:compared_against) { about } - let(:resource) { Decidim::UserBaseEntity } - it "updates the about text" do - expect { command.call }.to broadcast(:ok) - field = resource.last.reload.send(compared_field) - expect(field.is_a?(String) ? field : field[I18n.locale.to_s]).to eq(compared_against) - end - - it "fires the event" do - expect { command.call }.to have_enqueued_job.on_queue("spam_analysis") - .exactly(queue_size).times - end - - it "processes the event" do - perform_enqueued_jobs do - expect { command.call }.to change(Decidim::UserReport, :count).by_at_least(spam_count) - expect(Decidim::UserReport.count).to eq(spam_count) - end - end - end - - let(:data) do - { - "group" => { - name: "User group name", - nickname: "nickname", - email: "user@myrealdomain.org", - phone: "Y1fERVzL2F", - document_number: "123456780X", - about: - } - } - end - let(:organization) { create(:organization) } - let!(:system_user) { create(:user, :confirmed, email: Decidim::Ai::SpamDetection.reporting_user_email, organization:) } - let(:user) { create(:user, :confirmed, organization:) } - - let(:form) do - Decidim::UserGroupForm.from_params(**data).with_context(current_organization: organization, current_user: user) - end - - before do - Decidim::Ai::SpamDetection.user_registry.clear - Decidim::Ai::SpamDetection.user_registry.register_analyzer(name: :bayes, - strategy: Decidim::Ai::SpamDetection::Strategy::Bayes, - options: { adapter: :memory, params: {} }) - - Decidim::Ai::SpamDetection.user_classifier.train :ham, "I am a passionate Decidim Maintainer. It is nice to be here." - Decidim::Ai::SpamDetection.user_classifier.train :ham, "Yet I do not have an idea about what I am doing here." - Decidim::Ai::SpamDetection.user_classifier.train :ham, "Maybe You would understand better, and you would not get blocked as i did." - Decidim::Ai::SpamDetection.user_classifier.train :ham, "Just kidding, I needed some Ham to make an omelette." - - Decidim::Ai::SpamDetection.user_classifier.train :spam, "You are the lucky winner! Claim your holiday prize." - end - - shared_examples "test submitted data" do - context "when spam content is added" do - let(:about) { "Claim your prize today so you can win." } - - include_examples "user content submitted to spam analysis" do - let(:spam_count) { 1 } - end - end - - context "when regular content is added" do - let(:about) { "Very nice idea that is not going to be blocked" } - - include_examples "user content submitted to spam analysis" do - let(:spam_count) { 0 } - end - end - end - - context "when updating the account" do - let(:user_group) { create(:user_group, organization:) } - let(:command) { Decidim::UpdateUserGroup.new(form, user_group) } - - include_examples "test submitted data" - end - - context "when creates the account" do - let(:command) { Decidim::CreateUserGroup.new(form) } - - include_examples "test submitted data" - end -end diff --git a/spec/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job_spec.rb b/spec/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job_spec.rb index a3b1f8e..f4203ba 100644 --- a/spec/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job_spec.rb +++ b/spec/jobs/decidim/ai/spam_detection/generic_spam_analyzer_job_spec.rb @@ -28,4 +28,4 @@ expect(obj.send(:reporting_user)).to eq user_two end end -end \ No newline at end of file +end diff --git a/spec/lib/decidim/ai/spam_detection/importer/database_spec.rb b/spec/lib/decidim/ai/spam_detection/importer/database_spec.rb index 1700ec5..0cb1dda 100644 --- a/spec/lib/decidim/ai/spam_detection/importer/database_spec.rb +++ b/spec/lib/decidim/ai/spam_detection/importer/database_spec.rb @@ -11,6 +11,30 @@ Decidim::Ai::SpamDetection.resource_models = resources end + shared_examples "some resources are being spam" do + before do + Decidim::Ai::SpamDetection.resource_models = resource_models + allow(Decidim::Ai::SpamDetection).to receive(:resource_classifier).and_return(instance) + end + + let(:reporting_user) { author } + let(:spam_count) { 2 } + let!(:parent) { create(:report, reason: "parent_hidden", user: reporting_user, moderation: create(:moderation, :hidden, reportable: resources.last)) } + Decidim::Report::REASONS.excluding("parent_hidden").each do |reason| + let!(:report) { create(:report, reason:, user: reporting_user, moderation: create(:moderation, :hidden, reportable:)) } + + it "successfully loads the dataset when there are resources marked as #{reason}" do + allow(instance).to receive(:train) + + described_class.call + + expect(instance).to have_received(:train).with(:ham, anything).at_least(training - spam_count) + expect(instance).to have_received(:train).with(:spam, anything).at_least(spam_count) + expect(instance).to have_received(:train).with(:spam, "Hidden resource").at_least(1) + end + end + end + shared_examples "resource is being indexed" do let(:organization) { create(:organization) } let!(:author) { create(:user, organization:) } @@ -56,67 +80,64 @@ let(:manifest_name) { "meetings" } let(:training) { 20 } - let!(:meetings) do - create_list(:meeting, 4, component:, author:, - title: { en: "Some proposal that is not blocked" }, - description: { en: "The body for the meeting." }) - end + let!(:reportable) { create(:meeting, component:, author:, title: { en: "Hidden resource" }) } + let!(:resources) { create_list(:meeting, 3, component:, author:) } + let(:resource_models) { { "Decidim::Meetings::Meeting" => "Decidim::Ai::SpamDetection::Resource::Meeting" } } include_examples "resource is being indexed" + include_examples "some resources are being spam" do + let(:spam_count) { 5 } + end end context "when trained model is Decidim::Proposals::Proposal" do let(:manifest_name) { "proposals" } let(:training) { 8 } - let!(:proposals) do - create_list(:proposal, 4, - :published, - component:, - users: [author], - title: "Some proposal that is not blocked", - body: "The body for the proposal.") - end + let!(:reportable) { create(:proposal, :published, component:, users: [author], title: { en: "Hidden resource" }) } + let!(:resources) { create_list(:proposal, 3, :published, component:, users: [author]) } let(:resource_models) { { "Decidim::Proposals::Proposal" => "Decidim::Ai::SpamDetection::Resource::Proposal" } } include_examples "resource is being indexed" + include_examples "some resources are being spam" end context "when trained model is Decidim::Proposals::CollaborativeDraft" do let(:manifest_name) { "proposals" } let(:training) { 8 } - let!(:collaborative_drafts) do - create_list(:collaborative_draft, 4, - component:, - users: [author], - title: "Some draft that is not blocked", - body: "The body for the proposal.") - end + let!(:reportable) { create(:collaborative_draft, component:, users: [author], title: "Hidden resource") } + let!(:resources) { create_list(:collaborative_draft, 3, component:, users: [author]) } let(:resource_models) { { "Decidim::Proposals::CollaborativeDraft" => "Decidim::Ai::SpamDetection::Resource::CollaborativeDraft" } } include_examples "resource is being indexed" + include_examples "some resources are being spam" end context "when trained model is Decidim::Debates::Debate" do let(:manifest_name) { "debates" } let(:training) { 8 } - let!(:debates) do - create_list(:debate, 4, + let!(:reportable) do + create(:debate, + author:, component:, + title: { en: "Hidden resource" }) + end + let!(:resources) do + create_list(:debate, 3, author:, component:, - title: { en: "Some proposal that is not blocked" }, - description: { en: "The body for the meeting." }) + title: { en: "Some proposal that is not blocked" }) end let(:resource_models) { { "Decidim::Debates::Debate" => "Decidim::Ai::SpamDetection::Resource::Debate" } } include_examples "resource is being indexed" + include_examples "some resources are being spam" end context "when trained model is Decidim::User" do let(:tested) { 3 } - let(:training) { tested + 1 } # tested + author in shared example + let(:training) { 4 } # tested + author in shared example let!(:user) { create_list(:user, tested, organization:, about: "Something about me") } let(:resource_models) { { "Decidim::User" => "Decidim::Ai::SpamDetection::Resource::UserBaseEntity" } } @@ -129,20 +150,4 @@ end end end - - context "when trained model is Decidim::UserGroup" do - let(:tested) { 3 } - let(:training) { tested + 1 } # tested + author in shared example - - let!(:user) { create_list(:user_group, tested, organization:) } - let(:resource_models) { { "Decidim::UserGroup" => "Decidim::Ai::SpamDetection::Resource::UserBaseEntity" } } - - include_examples "resource is being indexed" do - let(:instance) { Decidim::Ai::SpamDetection::Service.new(registry: Decidim::Ai::SpamDetection.user_registry) } - - before do - allow(Decidim::Ai::SpamDetection).to receive(:user_classifier).and_return(instance) - end - end - end end diff --git a/spec/shared/events_examples.rb b/spec/shared/events_examples.rb index 5dff470..6cdfc2d 100644 --- a/spec/shared/events_examples.rb +++ b/spec/shared/events_examples.rb @@ -39,6 +39,28 @@ expect(Decidim::Report.count).to eq(spam_count) end end + + it "hides automatically the resource" do + allow(Decidim::Ai::SpamDetection).to receive(:hide_reported_resources_automatically).and_return(true) + perform_enqueued_jobs do + expect { command.call }.to change(Decidim::Report, :count).by(spam_count) + expect(Decidim::Report.count).to eq(spam_count) + # We are reusing the spec for Valid and invalid content. We are just checking that the resource is hidden if the + # resource is spam + expect(resource.last.hidden?).to eq(spam_count == 1) + end + end + + it "keps the resource visible" do + allow(Decidim::Ai::SpamDetection).to receive(:hide_reported_resources_automatically).and_return(false) + perform_enqueued_jobs do + expect { command.call }.to change(Decidim::Report, :count).by(spam_count) + expect(Decidim::Report.count).to eq(spam_count) + # We are reusing the spec for Valid and invalid content. We are just checking that the resource is not hidden if the + # setting is set to not hide spam content + expect(resource.last.hidden?).to be(false) + end + end end shared_examples "initiatives spam analysis" do @@ -52,7 +74,7 @@ let(:compared_against) { description } let(:resource) { Decidim::Initiative } let(:component) { nil } - let!(:participatory_space) { initiative } + let(:participatory_space) { initiative } end end @@ -73,8 +95,9 @@ shared_examples "debates spam analysis" do let(:manifest_name) { "debates" } - let(:scope) { create(:scope, organization:) } - let(:category) { create(:category, participatory_space:) } + let(:taxonomizations) do + 2.times.map { build(:taxonomization, taxonomy: create(:taxonomy, :with_parent, organization:), taxonomizable: nil) } + end context "when spam content is added" do let(:description) { "Claim your prize today so you can win." } @@ -131,8 +154,9 @@ shared_examples "meetings spam analysis" do let(:manifest_name) { "meetings" } - let(:scope) { create(:scope, organization:) } - let(:category) { create(:category, participatory_space:) } + let(:taxonomizations) do + 2.times.map { build(:taxonomization, taxonomy: create(:taxonomy, :with_parent, organization:), taxonomizable: nil) } + end context "when spam content is added" do let(:description) { "Claim your prize today so you can win." } @@ -161,7 +185,6 @@ shared_examples "proposal spam analysis" do let(:manifest_name) { "proposals" } - let(:user_group) { nil } context "when spam content is added" do let(:body) { "Claim your prize today so you can win." } @@ -189,8 +212,6 @@ end shared_examples "Collaborative draft spam analysis" do - let(:user_group) { nil } - context "when spam content is added" do let(:body) { "Claim your prize today so you can win." } let(:title) { "You are the Lucky winner" }