Skip to content

Commit

Permalink
Release 1.1.0 (#27)
Browse files Browse the repository at this point in the history
* Feature/mails admin revamp (#26)

* Update CI

* Don't use decidim commands

* Add organizations to results

* Send a digest to admins by mail

* Fix offenses

* Use bundle exec

* Remove duplicate precompile

* Run in assets precompile in ci

* Fix failing tests

* Normalize locales

* Update translations

* Revert "Update translations"

This reverts commit 1704e0d.

* Don't fail on invalid user

* Use status instead of results

* Send mail in a delegated job

* Fix offenses

* Add conditionnal in mailer

* Display probability in details and reason

Co-authored-by: paulinebessoles <[email protected]>

* Bump version (#28)

Co-authored-by: paulinebessoles <[email protected]>
  • Loading branch information
armandfardeau and paulinebessoles authored Feb 8, 2022
1 parent 684e1d4 commit e9a6ee3
Show file tree
Hide file tree
Showing 23 changed files with 428 additions and 57 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ jobs:
- uses: nanasess/[email protected]
- name: Run precompile if needed
run: |
if [[ -d ./spec/system && -n "$(ls -A ./spec/system)" ]]; then
rails assets:precompile
if [[ -d "app/views" ]] || [[ -d "spec/mailers" ]] || [[ -d "spec/system" ]]; then
cd "spec/decidim_dummy_app"
bundle exec rails assets:precompile
else
echo "No need to precompile assets since system folder is empty"
fi
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
decidim-spam_detection (1.0.0)
decidim-spam_detection (1.1.0)
decidim-core (~> 0.25)

GEM
Expand Down
19 changes: 19 additions & 0 deletions app/jobs/decidim/spam_detection/notify_admins.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Decidim
module SpamDetection
class NotifyAdmins < ApplicationJob
queue_as :default

def perform(results_hash)
results_hash.each do |id, result|
next if result.keys == [:nothing]

Decidim::Organization.find(id).admins.each do |admin|
Decidim::SpamDetection::SpamDetectionMailer.notify_detection(admin, result).deliver_later
end
end
end
end
end
end
19 changes: 19 additions & 0 deletions app/mailers/decidim/spam_detection/spam_detection_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Decidim
module SpamDetection
class SpamDetectionMailer < Decidim::ApplicationMailer
def notify_detection(user, results)
with_user(user) do
@reported_count = results[:reported_user]
@blocked_count = results[:blocked_user]
@organization = user.organization
@user = user

subject = I18n.t("notify_detection.subject", scope: "decidim.spam_detection_mailer")
mail(to: @user.email, subject: subject)
end
end
end
end
end
26 changes: 23 additions & 3 deletions app/services/decidim/spam_detection/mark_users_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def initialize
.where(admin: false, blocked: false, deleted_at: nil)
.where("(extended_data #> '{spam_detection, unreported_at}') is null")
.where("(extended_data #> '{spam_detection, unblocked_at}') is null")
@results = []
@results = {}
end

def self.call
Expand All @@ -38,11 +38,15 @@ def ask_and_mark
spam_probability_array = Decidim::SpamDetection::ApiProxy.request(cleaned_users)

mark_spam_users(merge_response_with_users(spam_probability_array))
notify_admins!
end

def mark_spam_users(probability_array)
probability_array.each do |probability_hash|
@results << Decidim::SpamDetection::SpamUserCommandAdapter.call(probability_hash).result
result = Decidim::SpamDetection::SpamUserCommandAdapter.call(probability_hash).result
organization_id = probability_hash["decidim_organization_id"]

add_to_results(organization_id.to_s, result)
end
end

Expand All @@ -56,7 +60,23 @@ def merge_response_with_users(response)
end

def status
@results.tally
@results.each_with_object({}) do |result, hash|
hash[result[0]] = result[1].tally
end
end

def notify_admins!
Decidim::SpamDetection::NotifyAdmins.perform_later(status)
end

private

def add_to_results(organization_id, result)
if @results[organization_id]
@results[organization_id] << result
else
@results[organization_id] = [result]
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<p class="email-greeting"><%= t(".hello", name: @user.name) %></p>
<p><%= t(".intro") %></p>

<% if @reported_count.present? %>
<p>
<%= t(".reported_count", count: @reported_count) %>
</p>
<% end %>

<% if @blocked_count.present? %>
<p>
<%= t(".blocked_count", count: @blocked_count) %>
</p>
<% end %>
9 changes: 0 additions & 9 deletions config/assets.rb

This file was deleted.

2 changes: 1 addition & 1 deletion config/i18n-tasks.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---

base_locale: en
locales: [en]
locales: [en, fr, es, ca]

ignore_unused:
- "decidim.components.spam_detection.name"
Expand Down
16 changes: 16 additions & 0 deletions config/locales/ca.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
ca:
decidim:
components:
spam_detection:
name: SpamDetection
spam_detection:
spam_detection_mailer:
notify_detection:
blocked_count: blocked_count %{count}
hello: Hello %{name}
intro: Aquí teniu l'informe de la tasca de detecció de correu brossa
reported_count: reported_count %{count}
spam_detection_mailer:
notify_detection:
subject: Resum de detecció de correu brossa
10 changes: 10 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ en:
components:
spam_detection:
name: SpamDetection
spam_detection:
spam_detection_mailer:
notify_detection:
blocked_count: 'Blocked users count: %{count}'
hello: Hello %{name}
intro: Here is the report of the spam detection task
reported_count: 'Reported users count: %{count}'
spam_detection_mailer:
notify_detection:
subject: Spam detection digest
16 changes: 16 additions & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
es:
decidim:
components:
spam_detection:
name: SpamDetection
spam_detection:
spam_detection_mailer:
notify_detection:
blocked_count: blocked_count %{count}
hello: Hello %{name}
intro: Here is the report of the spam detection task
reported_count: reported_count %{count}
spam_detection_mailer:
notify_detection:
subject: Subject
16 changes: 16 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
fr:
decidim:
components:
spam_detection:
name: SpamDetection
spam_detection:
spam_detection_mailer:
notify_detection:
blocked_count: blocked_count %{count}
hello: Hello %{name}
intro: Here is the report of the spam detection task
reported_count: reported_count %{count}
spam_detection_mailer:
notify_detection:
subject: Subject
15 changes: 12 additions & 3 deletions lib/decidim/spam_detection/abstract_spam_user_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def call
raise NotImplementedError
end

def reason
raise NotImplementedError
end

def details
raise NotImplementedError
end

def moderation_user
moderation_admin_params = {
name: SPAM_USER[:name],
Expand Down Expand Up @@ -56,9 +64,10 @@ def create_moderation_admin(params)
end

def add_spam_detection_metadata!(metadata)
@user.update!(extended_data: @user.extended_data
.dup
.deep_merge("spam_detection" => metadata))
@user.extended_data = @user.extended_data
.dup
.deep_merge("spam_detection" => metadata)
@user.save(validate: false)
end
end
end
Expand Down
64 changes: 48 additions & 16 deletions lib/decidim/spam_detection/block_spam_user_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,60 @@ class BlockSpamUserCommand < Decidim::SpamDetection::AbstractSpamUserCommand
prepend Decidim::SpamDetection::Command

def call
form = form(Decidim::Admin::BlockUserForm).from_params(
justification: "The user was blocked because of a high spam probability by Decidim spam detection bot"
)
ActiveRecord::Base.transaction do
create_user_moderation
block!
register_justification!
notify_user!
add_spam_detection_metadata!({ "blocked_at" => Time.current, "spam_probability" => @probability })
end

moderator = @moderator
user = @user
Rails.logger.info("User with id #{@user["id"]} was blocked for spam with a probability of #{@probability}%")

form.define_singleton_method(:user) { user }
form.define_singleton_method(:current_user) { moderator }
form.define_singleton_method(:blocking_user) { moderator }

Decidim::Admin::BlockUser.call(form)
:ok
end

add_spam_detection_metadata!({
"blocked_at" => Time.current,
"spam_probability" => @probability
})
private

def create_user_moderation
@user.create_user_moderation
Rails.logger.info("User with id #{@user["id"]} was blocked for spam")
end

:ok
def register_justification!
UserBlock.create!(justification: reason, user: @user, blocking_user: @moderator)
end

def notify_user!
Decidim::BlockUserJob.perform_later(@user, reason)
end

def block!
Decidim.traceability.perform_action!(
"block",
@user,
@moderator,
extra: {
reportable_type: @user.class.name,
current_justification: reason
},
resource: {
# Make sure the action log entry gets the original user name instead
# of "Blocked user". Otherwise the log entries would show funny
# messages such as "Mr. Admin blocked user Blocked user"-
title: @user.name
}
) do
@user.blocked = true
@user.blocked_at = Time.current
@user.blocking = @current_blocking
@user.extended_data["user_name"] = @user.name
@user.name = "Blocked user"
@user.save!
end
end

def reason
"The user was blocked because of a high spam probability by Decidim spam detection bot with a probability of #{@probability}%"
end
end
end
Expand Down
50 changes: 32 additions & 18 deletions lib/decidim/spam_detection/report_spam_user_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,43 @@ class ReportSpamUserCommand < Decidim::SpamDetection::AbstractSpamUserCommand
prepend Decidim::SpamDetection::Command

def call
form = form(Decidim::ReportForm).from_params(
reason: "spam",
details: "The user was marked as spam by Decidim spam detection bot"
)
ActiveRecord::Base.transaction do
find_or_create_moderation!
create_report!
update_report_count!
add_spam_detection_metadata!({ "reported_at" => Time.current, "spam_probability" => @probability })
end

current_organization = @user.organization
moderator = @moderator
user = @user
Rails.logger.info("User with id #{@user.id} was reported for spam with a probability of #{@probability}%")

report = Decidim::CreateUserReport.new(form, user, moderator)
report.define_singleton_method(:current_organization) { current_organization }
report.define_singleton_method(:current_user) { moderator }
report.define_singleton_method(:reportable) { user }
report.call
:ok
end

add_spam_detection_metadata!({
"reported_at" => Time.current,
"spam_probability" => @probability
})
private

Rails.logger.info("User with id #{user.id} was reported for spam")
def reason
"spam"
end

:ok
def details
"The user was marked as spam by Decidim spam detection bot with a probability of #{@probability}%"
end

def find_or_create_moderation!
@moderation = UserModeration.find_or_create_by!(user: @user)
end

def create_report!
@report = UserReport.create!(
moderation: @moderation,
user: @moderator,
reason: reason,
details: details
)
end

def update_report_count!
@moderation.update!(report_count: @moderation.report_count + 1)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/decidim/spam_detection/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Decidim
# This holds the decidim-spam_detection version.
module SpamDetection
def self.version
"1.0.0"
"1.1.0"
end

def self.decidim_version
Expand Down
Loading

0 comments on commit e9a6ee3

Please sign in to comment.