decidim-spam_detection 1.0.0 → 1.1.0

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: 7a68cdcfc4bee9d6fe8d391eb22a121b2f7cfb2a47557c1081b4ae47e649fc7f
4
- data.tar.gz: b7ee10f5d795d9044c7bd0d6270d899f3ce90e72496221739dad6715cd287de8
3
+ metadata.gz: 38cc3310b2ed4c7e48cadea2c1bf9f0ff86d8f28bad7b3e04398d5922598442d
4
+ data.tar.gz: be191b16b6827c2e6963b72578fe899d1feace76156b87cb246928dc869619d3
5
5
  SHA512:
6
- metadata.gz: 921412beab2eb7bbf993bb1f6f02f95556ebdd7bb61ac18695764176762a870e48ac572a9f86b0cc4dcdc91a2ed09a6786d3e54b7f8b14f4b56e912992c8a9ba
7
- data.tar.gz: d46133286084b2a2c353a8fb50a0fc0460f299925e8335c791f6f2472d66c9cf2ea70ef647f616645105584630f798573ef988ae4c862c1d3a2dc713e87b4d8d
6
+ metadata.gz: ef0c0fcc58dfdb427725cc53ad5a3fa2829b0482180e4b311427a483345b97f09ec90d55ffdcfaf778903ed00913bf17976ae56e2a9fb13deb17605cf45c0425
7
+ data.tar.gz: 9d6b782f0b236cd000b1bf361b5d83524c037da23fa22aa779321f5c09fafbc849d45d713c965b2e9a6eb2a37d465565e91b33bfcff0a1e73436065ee76265b6
@@ -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,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module SpamDetection
5
+ class SpamDetectionMailer < Decidim::ApplicationMailer
6
+ def notify_detection(user, results)
7
+ with_user(user) do
8
+ @reported_count = results[:reported_user]
9
+ @blocked_count = results[:blocked_user]
10
+ @organization = user.organization
11
+ @user = user
12
+
13
+ subject = I18n.t("notify_detection.subject", scope: "decidim.spam_detection_mailer")
14
+ mail(to: @user.email, subject: subject)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ 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,14 @@
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
+ <% end %>
9
+
10
+ <% if @blocked_count.present? %>
11
+ <p>
12
+ <%= t(".blocked_count", count: @blocked_count) %>
13
+ </p>
14
+ <% end %>
@@ -1,7 +1,7 @@
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"
@@ -0,0 +1,16 @@
1
+ ---
2
+ ca:
3
+ decidim:
4
+ components:
5
+ spam_detection:
6
+ name: SpamDetection
7
+ spam_detection:
8
+ spam_detection_mailer:
9
+ notify_detection:
10
+ blocked_count: blocked_count %{count}
11
+ hello: Hello %{name}
12
+ intro: Aquí teniu l'informe de la tasca de detecció de correu brossa
13
+ reported_count: reported_count %{count}
14
+ spam_detection_mailer:
15
+ notify_detection:
16
+ subject: Resum de detecció de correu brossa
@@ -4,3 +4,13 @@ en:
4
4
  components:
5
5
  spam_detection:
6
6
  name: SpamDetection
7
+ spam_detection:
8
+ spam_detection_mailer:
9
+ notify_detection:
10
+ blocked_count: 'Blocked users count: %{count}'
11
+ hello: Hello %{name}
12
+ intro: Here is the report of the spam detection task
13
+ reported_count: 'Reported users count: %{count}'
14
+ spam_detection_mailer:
15
+ notify_detection:
16
+ subject: Spam detection digest
@@ -0,0 +1,16 @@
1
+ ---
2
+ es:
3
+ decidim:
4
+ components:
5
+ spam_detection:
6
+ name: SpamDetection
7
+ spam_detection:
8
+ spam_detection_mailer:
9
+ notify_detection:
10
+ blocked_count: blocked_count %{count}
11
+ hello: Hello %{name}
12
+ intro: Here is the report of the spam detection task
13
+ reported_count: reported_count %{count}
14
+ spam_detection_mailer:
15
+ notify_detection:
16
+ subject: Subject
@@ -0,0 +1,16 @@
1
+ ---
2
+ fr:
3
+ decidim:
4
+ components:
5
+ spam_detection:
6
+ name: SpamDetection
7
+ spam_detection:
8
+ spam_detection_mailer:
9
+ notify_detection:
10
+ blocked_count: blocked_count %{count}
11
+ hello: Hello %{name}
12
+ intro: Here is the report of the spam detection task
13
+ reported_count: reported_count %{count}
14
+ spam_detection_mailer:
15
+ notify_detection:
16
+ subject: Subject
@@ -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
+ "The user was blocked because of a high spam probability by Decidim spam detection bot with a probability of #{@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
+ "The user was marked as spam by Decidim spam detection bot with a probability of #{@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
- "1.0.0"
8
+ "1.1.0"
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: 1.0.0
4
+ version: 1.1.0
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-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: decidim-core
@@ -40,10 +40,15 @@ files:
40
40
  - app/commands/decidim/admin/unblock_user.rb
41
41
  - app/commands/decidim/admin/unreport_user.rb
42
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
43
45
  - app/services/decidim/spam_detection/mark_users_service.rb
44
- - config/assets.rb
46
+ - app/views/decidim/spam_detection/spam_detection_mailer/notify_detection.html.erb
45
47
  - config/i18n-tasks.yml
48
+ - config/locales/ca.yml
46
49
  - config/locales/en.yml
50
+ - config/locales/es.yml
51
+ - config/locales/fr.yml
47
52
  - lib/decidim/spam_detection.rb
48
53
  - lib/decidim/spam_detection/abstract_spam_user_command.rb
49
54
  - lib/decidim/spam_detection/admin.rb
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")