decidim-spam_detection 0.1.8 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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")