Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- uses: nanasess/setup-chromedriver@v2
- run: bundle exec rspec
name: RSpec
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
Expand Down
12 changes: 7 additions & 5 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@ gem "decidim", "~> 0.27.0"
gem "decidim-spam_detection", path: "."

gem "bootsnap", "~> 1.4"
gem "puma", ">= 5.5.1"
gem "puma", ">= 5.0.0"
gem "uglifier", "~> 4.1"
gem "webpacker", "6.0.0.rc.5"

group :development, :test do
gem "byebug", "~> 11.0", platform: :mri
gem "rubocop-faker"
gem "rubocop-performance", "~> 1.6.0"

gem "decidim-dev", "~> 0.27.0"
end

group :development do
gem "faker", "~> 2.14"
gem "letter_opener_web", "~> 1.3"
gem "letter_opener_web", "~> 1.4"
gem "listen", "~> 3.1"
gem "rubocop-faker"
gem "spring", "~> 2.0"
gem "spring-watcher-listen", "~> 2.0"
gem "web-console", "~> 4.0"
gem "web-console", "~> 3.7"
end

group :test do
gem "codecov", require: false
gem "webmock"
end
24 changes: 15 additions & 9 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,8 @@ GEM
rubocop-faker (1.1.0)
faker (>= 2.12.0)
rubocop (>= 0.82.0)
rubocop-performance (1.6.1)
rubocop (>= 0.71.0)
rubocop-rails (2.15.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
Expand Down Expand Up @@ -764,6 +766,8 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
uglifier (4.2.1)
execjs (>= 0.3.0, < 3)
unicode-display_width (2.6.0)
uri (0.13.1)
valid_email2 (2.3.1)
Expand All @@ -784,11 +788,11 @@ GEM
rexml (~> 3.2)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
railties (>= 5.0)
webmock (3.24.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
Expand Down Expand Up @@ -825,17 +829,19 @@ DEPENDENCIES
decidim-dev (~> 0.27.0)
decidim-spam_detection!
faker (~> 2.14)
letter_opener_web (~> 1.3)
letter_opener_web (~> 1.4)
listen (~> 3.1)
puma (>= 5.5.1)
puma (>= 5.0.0)
rubocop-faker
rubocop-performance (~> 1.6.0)
spring (~> 2.0)
spring-watcher-listen (~> 2.0)
web-console (~> 4.0)
webmock
uglifier (~> 4.1)
web-console (~> 3.7)
webpacker (= 6.0.0.rc.5)

RUBY VERSION
ruby 3.0.6p216

BUNDLED WITH
2.4.6
2.4.9
48 changes: 41 additions & 7 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@

require "decidim/dev/common_rake"

def js_configuration(path)
babel_file_path = File.join(Dir.pwd, "babel.config.json")
def install_module(path)
Dir.chdir(path) do
system("bundle exec rails railties:install:migrations")
system("bundle exec rake db:migrate")

# Temporary fix to overcome the issue with sass-embedded, see:
# https://github.com/decidim/decidim/pull/11074
system("npm i sass-embedded@~1.62.0")
end
end

# Temporary fix to overcome the issue with babel plugin updates, see:
# https://github.com/decidim/decidim/pull/10916
def fix_babel_config(path)
Dir.chdir(path) do
FileUtils.cp(babel_file_path, "babel.config.json")
babel_config = "#{Dir.pwd}/babel.config.json"
File.delete(babel_config) if File.exist?(babel_config)
FileUtils.cp("#{__dir__}/babel.config.json", Dir.pwd)
system("yarn add graphql-ws")
system("yarn add @tarekraafat/autocomplete.js")
system("yarn add @babel/plugin-proposal-private-methods")
Expand All @@ -15,13 +28,34 @@ def js_configuration(path)
end
end

def seed_db(path)
Dir.chdir(path) do
system("bundle exec rake db:seed")
end
end

desc "Generates a dummy app for testing"
task test_app: "decidim:generate_external_test_app" do
ENV["RAILS_ENV"] = "test"
js_configuration("spec/decidim_dummy_app")
fix_babel_config("spec/decidim_dummy_app")
install_module("spec/decidim_dummy_app")
end

desc "Generates a development app."
task development_app: "decidim:generate_external_development_app" do
js_configuration("development_app")
desc "Generates a development app"
task :development_app do
Bundler.with_original_env do
generate_decidim_app(
"development_app",
"--app_name",
"#{base_app_name}_development_app",
"--path",
"..",
"--recreate_db",
"--demo"
)
end

fix_babel_config("development_app")
install_module("development_app")
seed_db("development_app")
end
14 changes: 14 additions & 0 deletions lib/decidim/spam_detection/block_spam_user_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def block!
@user.blocking = @current_blocking
update_extended_data
@user.name = "Blocked user"
@user.nickname = generate_nickname
@user.save!
end
end
Expand All @@ -65,9 +66,22 @@ def reason
I18n.t("blocked_user.reason", probability: @probability)
end

def generate_nickname
max_attempts = 10

max_attempts.times do
random_key = SecureRandom.hex(5)
Comment thread
AyakorK marked this conversation as resolved.
nickname = "blocked_#{random_key}"
return nickname unless Decidim::User.exists?(nickname: nickname)
end

raise "Unable to generate a unique nickname after #{max_attempts} attempts."
Comment thread
AyakorK marked this conversation as resolved.
end

def update_extended_data
@user.extended_data = {} if @user.extended_data.nil?
@user.extended_data["user_name"] = @user.name
@user.extended_data["user_nickname"] = @user.nickname
end
end
end
Expand Down
68 changes: 52 additions & 16 deletions spec/lib/decidim/spam_detection/block_spam_user_command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,85 @@
module Decidim
module SpamDetection
describe BlockSpamUserCommand do
let(:subject) { described_class.call(user, spam_probabilty) }
subject { described_class.call(user, spam_probability) }

let(:organization) { create(:organization) }
let!(:user) { create(:user, organization: organization) }
let(:spam_probabilty) { 0.1 }
let(:spam_probability) { 0.1 }

describe "#call" do
shared_examples "a successful block" do
it "blocks the user" do
expect { subject }.to change(Decidim::UserBlock, :count)
expect { subject }.to change(Decidim::UserBlock, :count).by(1)
end

it "creates a log" do
expect { subject }.to change(Decidim::ActionLog, :count)
expect(Decidim::ActionLog.last.extra.dig("extra", "current_justification")).to eq("Our automatic spam account detection task has blocked you. If this is an error. Contact the platform administrators who will be able to restore your account.")
expect { subject }.to change(Decidim::ActionLog, :count).by(1)
expect(Decidim::ActionLog.last.extra.dig("extra", "current_justification"))
.to eq("Our automatic spam account detection task has blocked you. If this is an error. Contact the platform administrators who will be able to restore your account.")
end

it "create a moderation entry" do
expect { subject }.to change(Decidim::UserModeration, :count)
it "creates a moderation entry" do
expect { subject }.to change(Decidim::UserModeration, :count).by(1)
end

it "add spam detection metadata" do
it "adds spam detection metadata" do
subject

expect(user.reload.extended_data.dig("spam_detection", "blocked_at")).not_to be_nil
expect(user.reload.extended_data.dig("spam_detection", "spam_probability")).to eq(0.1)
expect(user.reload.extended_data.dig("spam_detection", "spam_probability")).to eq(spam_probability)
end

it "runs without error" do
expect(subject).to be_success
end

it "broadcast a result" do
it "broadcasts a result" do
expect(subject.result).to eq(:ok)
end
end

describe "#call" do
include_examples "a successful block"

context "when extended_data is nil" do
before do
user.update!(extended_data: nil)
end
before { user.update!(extended_data: nil) }

it "broadcast ok" do
it "broadcasts ok" do
expect(subject.result).to eq(:ok)
end
end

context "when nickname contains forbidden unicode characters" do
let!(:user) do
user = create(:user, organization: organization)
user.nickname = "forbıdden_nıckname"
user.save!(validate: false)
user
end

include_examples "a successful block"
end

context "when nickname contains emojis" do
let!(:user) do
user = create(:user, organization: organization)
user.nickname = "weird🤖name🚀"
user.save!(validate: false)
user
end

include_examples "a successful block"
end

context "when nickname contains strange accents" do
let!(:user) do
user = create(:user, organization: organization)
user.nickname = "nîcknäme_çurîeux"
user.save!(validate: false)
user
end

include_examples "a successful block"
end
end
end
end
Expand Down
Loading