decidim-spam_detection 0.1.8 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3445c988572081b0eee462ff8803ffe87071368c91a5f7709a29be6984e469da
4
- data.tar.gz: a60dddbac8f547c1df84889568471fc7fc1f1fed7e0bee9b0c69b20625885c9d
3
+ metadata.gz: 3734b1cecb038a80ab8905ab0cd7d9680a452b50627f0e5c5d92ee5a5e08c831
4
+ data.tar.gz: b1a7b24b904478f66d15d5bb28430aa9f1baff2da793d9517478004e1f6cd3e9
5
5
  SHA512:
6
- metadata.gz: 2540ab9036fe3c17f7b6652052a8f5e224ffb5f30afc150501bd0dcc0006d26c13e5191048aeee9980e5eb00492210f3216aef5007142b201803349fec46526a
7
- data.tar.gz: 2029c17054430ded82b4d9d97f8fa57ca14e60329db4168496bc4d8bebaf6d71246da3ac8cf788a0e28bb84845486170d81762c0f46d5301610607fd8ed17839
6
+ metadata.gz: 441ffd50f429c3131f7f646eed4ba74552714908b570ff62fb9b0916e48c40e338087ff3c53ca1761b14a1483eb1217c4f4f122d020db655cbd5bbaf6413dfe4
7
+ data.tar.gz: 153cc30f6568d4566a8dcf610a4b39128748dc7bc4debafd2a3c7f62c9b021d2cabe3b9322f367fd3a1893f23d463feada7f8fc16b885054ec3f3f2d2bbad3e4
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Decidim::SpamDetection
2
2
  [![codecov](https://codecov.io/gh/OpenSourcePolitics/decidim-spam_detection/branch/master/graph/badge.svg?token=eJu34XLlVu)](https://codecov.io/gh/OpenSourcePolitics/decidim-spam_detection)
3
- ![Tests](https://github.com/opensourcepolitics/decidim-spam_detection/actions/workflows/tests.yml/badge.svg)
4
- ![Tests](https://github.com/opensourcepolitics/decidim-spam_detection/actions/workflows/lint.yml/badge.svg)
3
+ ![Tests](https://github.com/opensourcepolitics/decidim-spam_detection/actions/workflows/ci_cd.yml/badge.svg)
5
4
 
6
5
  ## Usage
7
6
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module SpamDetection
5
+ class NotifyAdmins < ApplicationJob
6
+ queue_as :default
7
+
8
+ def perform(results_hash)
9
+ results_hash.each do |id, result|
10
+ next if result.keys == [:nothing]
11
+
12
+ Decidim::Organization.find(id).admins.each do |admin|
13
+ Decidim::SpamDetection::SpamDetectionMailer.notify_detection(admin, result).deliver_later
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module SpamDetection
5
+ class SpamDetectionMailer < Decidim::ApplicationMailer
6
+ helper_method :blocked_users_url, :reported_users_url
7
+
8
+ def notify_detection(user, results)
9
+ with_user(user) do
10
+ @reported_count = results[:reported_user]
11
+ @blocked_count = results[:blocked_user]
12
+ @organization = user.organization
13
+ @user = user
14
+
15
+ subject = I18n.t("notify_detection.subject", scope: "decidim.spam_detection_mailer")
16
+ mail(to: @user.email, subject: subject)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def blocked_users_url
23
+ decidim_admin.moderated_users_url(blocked: true, host: root_url)
24
+ end
25
+
26
+ def reported_users_url
27
+ decidim_admin.moderated_users_url(blocked: false, host: root_url)
28
+ end
29
+
30
+ def decidim_admin
31
+ Decidim::Admin::Engine.routes.url_helpers
32
+ end
33
+
34
+ def root_url
35
+ decidim.root_url(host: @user.organization.host)[0..-2]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -27,7 +27,7 @@ module Decidim
27
27
  .where(admin: false, blocked: false, deleted_at: nil)
28
28
  .where("(extended_data #> '{spam_detection, unreported_at}') is null")
29
29
  .where("(extended_data #> '{spam_detection, unblocked_at}') is null")
30
- @results = []
30
+ @results = {}
31
31
  end
32
32
 
33
33
  def self.call
@@ -38,11 +38,15 @@ module Decidim
38
38
  spam_probability_array = Decidim::SpamDetection::ApiProxy.request(cleaned_users)
39
39
 
40
40
  mark_spam_users(merge_response_with_users(spam_probability_array))
41
+ notify_admins!
41
42
  end
42
43
 
43
44
  def mark_spam_users(probability_array)
44
45
  probability_array.each do |probability_hash|
45
- @results << Decidim::SpamDetection::SpamUserCommandAdapter.call(probability_hash).result
46
+ result = Decidim::SpamDetection::SpamUserCommandAdapter.call(probability_hash).result
47
+ organization_id = probability_hash["decidim_organization_id"]
48
+
49
+ add_to_results(organization_id.to_s, result)
46
50
  end
47
51
  end
48
52
 
@@ -56,7 +60,23 @@ module Decidim
56
60
  end
57
61
 
58
62
  def status
59
- @results.tally
63
+ @results.each_with_object({}) do |result, hash|
64
+ hash[result[0]] = result[1].tally
65
+ end
66
+ end
67
+
68
+ def notify_admins!
69
+ Decidim::SpamDetection::NotifyAdmins.perform_later(status)
70
+ end
71
+
72
+ private
73
+
74
+ def add_to_results(organization_id, result)
75
+ if @results[organization_id]
76
+ @results[organization_id] << result
77
+ else
78
+ @results[organization_id] = [result]
79
+ end
60
80
  end
61
81
  end
62
82
  end
@@ -0,0 +1,16 @@
1
+ <p class="email-greeting"><%= t(".hello", name: @user.name) %></p>
2
+ <p><%= t(".intro") %></p>
3
+
4
+ <% if @reported_count.present? %>
5
+ <p>
6
+ <%= t(".reported_count", count: @reported_count) %>
7
+ </p>
8
+ <p><%= link_to(t(".reported_link"), reported_users_url ) %></p>
9
+ <% end %>
10
+
11
+ <% if @blocked_count.present? %>
12
+ <p>
13
+ <%= t(".blocked_count", count: @blocked_count) %>
14
+ </p>
15
+ <p><%= link_to(t(".blocked_link"), blocked_users_url ) %></p>
16
+ <% end %>
@@ -1,10 +1,12 @@
1
1
  ---
2
2
 
3
3
  base_locale: en
4
- locales: [en]
4
+ locales: [en, fr, es, ca]
5
5
 
6
6
  ignore_unused:
7
7
  - "decidim.components.spam_detection.name"
8
+ - blocked_user.*
9
+ - reported_user.*
8
10
 
9
11
  ignore_missing:
10
12
  - decidim.participatory_processes.scopes.global
@@ -0,0 +1,25 @@
1
+ ---
2
+ ca:
3
+ blocked_user:
4
+ reason: L'usuari ha estat bloquejat a causa d'una alta probabilitat de spam per
5
+ la tasca de detecció automàtica de spam de Decidim amb una probabilitat de %{probability}%
6
+ decidim:
7
+ components:
8
+ spam_detection:
9
+ name: DeteccioSpam
10
+ spam_detection:
11
+ spam_detection_mailer:
12
+ notify_detection:
13
+ blocked_count: Comptes de spam bloquejats %{count}
14
+ blocked_link: Consulteu la llista de tots els comptes bloquejats
15
+ hello: Hola %{name}
16
+ intro: Aquí teniu l'informe de la tasca de detecció de spam
17
+ reported_count: Comptes blocs de %{count}
18
+ reported_link: Consulteu la llista de tots els comptes reportats al lloc
19
+ spam_detection_mailer:
20
+ notify_detection:
21
+ subject: Informe de la tasca automàtica detecció de spam
22
+ reported_user:
23
+ details: L'usuari s'ha marcat com spam a causa d'una alta probabilitat de spam
24
+ per la tasca de detecció automàtica de spam de Decidim amb una probabilitat
25
+ de %{probability}%
@@ -1,6 +1,24 @@
1
1
  ---
2
2
  en:
3
+ blocked_user:
4
+ reason: The user was blocked because of a high spam probability by the automated
5
+ spam detection task with a probability of %{probability}%
3
6
  decidim:
4
7
  components:
5
8
  spam_detection:
6
9
  name: SpamDetection
10
+ spam_detection:
11
+ spam_detection_mailer:
12
+ notify_detection:
13
+ blocked_count: 'Spam accounts blocked: %{count}'
14
+ blocked_link: See the list of all blocked accounts
15
+ hello: Hello %{name}
16
+ intro: Here is the report of the automated spam detection task.
17
+ reported_count: 'Spam accounts reported: %{count}'
18
+ reported_link: See the list of all reported accounts
19
+ spam_detection_mailer:
20
+ notify_detection:
21
+ subject: Automated spam detection task digest
22
+ reported_user:
23
+ details: The user was reported because of a high spam probability by the automated
24
+ spam detection task with a probability of %{probability}%
@@ -0,0 +1,24 @@
1
+ ---
2
+ es:
3
+ blocked_user:
4
+ reason: El usuario fue bloqueado debido a una alta probabilidad de spam por la
5
+ tarea de detección automática de spam con una probabilidad de %{probability}%
6
+ decidim:
7
+ components:
8
+ spam_detection:
9
+ name: DeteccionSpam
10
+ spam_detection:
11
+ spam_detection_mailer:
12
+ notify_detection:
13
+ blocked_count: 'Cuentas de spam bloqueadas : %{count}'
14
+ blocked_link: Ver la lista de todas las cuentas bloqueadas
15
+ hello: Hola %{name}
16
+ intro: Aquí está el informe de la tarea de detección automática de spam.
17
+ reported_count: Cuentas de spam señaladas %{count}
18
+ reported_link: Ver la lista de cuentas señaladas
19
+ spam_detection_mailer:
20
+ notify_detection:
21
+ subject: Informe de la tarea automática detección de spam
22
+ reported_user:
23
+ details: El usuario fue señalado debido a una alta probabilidad de spam por la
24
+ tarea de detección automática de spam con una probabilidad de %{probability}%
@@ -0,0 +1,24 @@
1
+ ---
2
+ fr:
3
+ blocked_user:
4
+ reason: L'utilisateur a été bloqué en raison d'une forte probabilité de spam par
5
+ la tâche de détection automatique de spam avec une probabilité de %{probability}%
6
+ decidim:
7
+ components:
8
+ spam_detection:
9
+ name: DetectionSpam
10
+ spam_detection:
11
+ spam_detection_mailer:
12
+ notify_detection:
13
+ blocked_count: 'Comptes spam bloqués : %{count}'
14
+ blocked_link: Voir la liste de tous les comptes bloqués du site
15
+ hello: Bonjour %{name}
16
+ intro: Voici le rapport de la tâche de détection automatisée des spams.
17
+ reported_count: 'Comptes spam signalés : %{count}'
18
+ reported_link: Voir la liste de tous les comptes signalés
19
+ spam_detection_mailer:
20
+ notify_detection:
21
+ subject: Rapport de la tâche de détection automatique de spam
22
+ reported_user:
23
+ details: L'utilisateur a été signalé en raison d'une forte probabilité de spam
24
+ par la tâche de détection automatique de spam avec une probabilité de %{probability}%
@@ -24,6 +24,14 @@ module Decidim
24
24
  raise NotImplementedError
25
25
  end
26
26
 
27
+ def reason
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def details
32
+ raise NotImplementedError
33
+ end
34
+
27
35
  def moderation_user
28
36
  moderation_admin_params = {
29
37
  name: SPAM_USER[:name],
@@ -56,9 +64,10 @@ module Decidim
56
64
  end
57
65
 
58
66
  def add_spam_detection_metadata!(metadata)
59
- @user.update!(extended_data: @user.extended_data
60
- .dup
61
- .deep_merge("spam_detection" => metadata))
67
+ @user.extended_data = @user.extended_data
68
+ .dup
69
+ .deep_merge("spam_detection" => metadata)
70
+ @user.save(validate: false)
62
71
  end
63
72
  end
64
73
  end
@@ -9,28 +9,60 @@ module Decidim
9
9
  prepend Decidim::SpamDetection::Command
10
10
 
11
11
  def call
12
- form = form(Decidim::Admin::BlockUserForm).from_params(
13
- justification: "The user was blocked because of a high spam probability by Decidim spam detection bot"
14
- )
12
+ ActiveRecord::Base.transaction do
13
+ create_user_moderation
14
+ block!
15
+ register_justification!
16
+ notify_user!
17
+ add_spam_detection_metadata!({ "blocked_at" => Time.current, "spam_probability" => @probability })
18
+ end
15
19
 
16
- moderator = @moderator
17
- user = @user
20
+ Rails.logger.info("User with id #{@user["id"]} was blocked for spam with a probability of #{@probability}%")
18
21
 
19
- form.define_singleton_method(:user) { user }
20
- form.define_singleton_method(:current_user) { moderator }
21
- form.define_singleton_method(:blocking_user) { moderator }
22
-
23
- Decidim::Admin::BlockUser.call(form)
22
+ :ok
23
+ end
24
24
 
25
- add_spam_detection_metadata!({
26
- "blocked_at" => Time.current,
27
- "spam_probability" => @probability
28
- })
25
+ private
29
26
 
27
+ def create_user_moderation
30
28
  @user.create_user_moderation
31
- Rails.logger.info("User with id #{@user["id"]} was blocked for spam")
29
+ end
32
30
 
33
- :ok
31
+ def register_justification!
32
+ UserBlock.create!(justification: reason, user: @user, blocking_user: @moderator)
33
+ end
34
+
35
+ def notify_user!
36
+ Decidim::BlockUserJob.perform_later(@user, reason)
37
+ end
38
+
39
+ def block!
40
+ Decidim.traceability.perform_action!(
41
+ "block",
42
+ @user,
43
+ @moderator,
44
+ extra: {
45
+ reportable_type: @user.class.name,
46
+ current_justification: reason
47
+ },
48
+ resource: {
49
+ # Make sure the action log entry gets the original user name instead
50
+ # of "Blocked user". Otherwise the log entries would show funny
51
+ # messages such as "Mr. Admin blocked user Blocked user"-
52
+ title: @user.name
53
+ }
54
+ ) do
55
+ @user.blocked = true
56
+ @user.blocked_at = Time.current
57
+ @user.blocking = @current_blocking
58
+ @user.extended_data["user_name"] = @user.name
59
+ @user.name = "Blocked user"
60
+ @user.save!
61
+ end
62
+ end
63
+
64
+ def reason
65
+ I18n.t("blocked_user.reason", probability: @probability)
34
66
  end
35
67
  end
36
68
  end
@@ -9,29 +9,43 @@ module Decidim
9
9
  prepend Decidim::SpamDetection::Command
10
10
 
11
11
  def call
12
- form = form(Decidim::ReportForm).from_params(
13
- reason: "spam",
14
- details: "The user was marked as spam by Decidim spam detection bot"
15
- )
12
+ ActiveRecord::Base.transaction do
13
+ find_or_create_moderation!
14
+ create_report!
15
+ update_report_count!
16
+ add_spam_detection_metadata!({ "reported_at" => Time.current, "spam_probability" => @probability })
17
+ end
16
18
 
17
- current_organization = @user.organization
18
- moderator = @moderator
19
- user = @user
19
+ Rails.logger.info("User with id #{@user.id} was reported for spam with a probability of #{@probability}%")
20
20
 
21
- report = Decidim::CreateUserReport.new(form, user, moderator)
22
- report.define_singleton_method(:current_organization) { current_organization }
23
- report.define_singleton_method(:current_user) { moderator }
24
- report.define_singleton_method(:reportable) { user }
25
- report.call
21
+ :ok
22
+ end
26
23
 
27
- add_spam_detection_metadata!({
28
- "reported_at" => Time.current,
29
- "spam_probability" => @probability
30
- })
24
+ private
31
25
 
32
- Rails.logger.info("User with id #{user.id} was reported for spam")
26
+ def reason
27
+ "spam"
28
+ end
33
29
 
34
- :ok
30
+ def details
31
+ I18n.t("reported_user.details", probability: @probability)
32
+ end
33
+
34
+ def find_or_create_moderation!
35
+ @moderation = UserModeration.find_or_create_by!(user: @user)
36
+ end
37
+
38
+ def create_report!
39
+ @report = UserReport.create!(
40
+ moderation: @moderation,
41
+ user: @moderator,
42
+ reason: reason,
43
+ details: details
44
+ )
45
+ end
46
+
47
+ def update_report_count!
48
+ @moderation.update!(report_count: @moderation.report_count + 1)
35
49
  end
36
50
  end
37
51
  end
@@ -5,7 +5,7 @@ module Decidim
5
5
  # This holds the decidim-spam_detection version.
6
6
  module SpamDetection
7
7
  def self.version
8
- "0.1.8"
8
+ "1.1.1"
9
9
  end
10
10
 
11
11
  def self.decidim_version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-spam_detection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Armand Fardeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-08 00:00:00.000000000 Z
11
+ date: 2022-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: decidim-core
@@ -24,7 +24,10 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.25'
27
- description: "."
27
+ description: " SpamDetection is a detection bot made by OpenSourcePolitics. \n It
28
+ works with a spam detection service (https://github.com/OpenSourcePolitics/spam_detection)
29
+ \n which marks the user with a spam probability score, \n between 0.7 and 0.99
30
+ it is probable, and above 0.99 it is very sure.\n"
28
31
  email:
29
32
  - fardeauarmand@gmail.com
30
33
  executables: []
@@ -37,10 +40,15 @@ files:
37
40
  - app/commands/decidim/admin/unblock_user.rb
38
41
  - app/commands/decidim/admin/unreport_user.rb
39
42
  - app/jobs/decidim/spam_detection/mark_users_job.rb
43
+ - app/jobs/decidim/spam_detection/notify_admins.rb
44
+ - app/mailers/decidim/spam_detection/spam_detection_mailer.rb
40
45
  - app/services/decidim/spam_detection/mark_users_service.rb
41
- - config/assets.rb
46
+ - app/views/decidim/spam_detection/spam_detection_mailer/notify_detection.html.erb
42
47
  - config/i18n-tasks.yml
48
+ - config/locales/ca.yml
43
49
  - config/locales/en.yml
50
+ - config/locales/es.yml
51
+ - config/locales/fr.yml
44
52
  - lib/decidim/spam_detection.rb
45
53
  - lib/decidim/spam_detection/abstract_spam_user_command.rb
46
54
  - lib/decidim/spam_detection/admin.rb
@@ -55,7 +63,7 @@ files:
55
63
  - lib/decidim/spam_detection/test/factories.rb
56
64
  - lib/decidim/spam_detection/version.rb
57
65
  - lib/tasks/decidim_spam_detection.rake
58
- homepage: https://github.com/decidim/decidim-module-spam_detection
66
+ homepage: https://github.com/OpenSourcePolitics/decidim-spam_detection
59
67
  licenses:
60
68
  - AGPL-3.0
61
69
  metadata: {}
data/config/assets.rb DELETED
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- base_path = File.expand_path("..", __dir__)
4
-
5
- Decidim::Webpacker.register_path("#{base_path}/app/packs")
6
- Decidim::Webpacker.register_entrypoints(
7
- decidim_spam_detection: "#{base_path}/app/packs/entrypoints/decidim_spam_detection.js"
8
- )
9
- Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/spam_detection/spam_detection")