decidim-cdtb 0.1.3 → 0.1.6

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: d908d1cc4021da9869dd10cacb1fe06b360301d4e13f1a70a55fdc90a2712b6a
4
- data.tar.gz: e7a0c808803bbbd6dc75e5bdfaee7b3acfb1311c085f17eb41a9de32fc7795fa
3
+ metadata.gz: 241f6ab9b3dcf2a9c90d13e458459776a5cedf5d0beff5ffbe9114b0c0f687ba
4
+ data.tar.gz: 2d9a4ef96c973b47296869acf12083a4f5862fdab7e7135e6ad36e6674115edc
5
5
  SHA512:
6
- metadata.gz: 20ddde6eddf59ab12b7ca8d6f489692a04183331f0c1ef496b199b4350cdd103d2b23ca94329199d36f2a9e7222ea0c3269da25648ec0acb47bdde6b38666b92
7
- data.tar.gz: 2dd41a8a1f79ffd4506c6b18d58393d3a88d8a021e0acf05cfbd4e4ac1dcc22250294c8de29d7168c2fce29bf2d2df71c0b9905414a3df1e28991aa665be8d36
6
+ metadata.gz: 37c3ba1e514d44cecf61948a84f89b16c01dd67f7993b972fda6f6b006997b0afaabf3dcacf312ff85a9ef142d6f1576dd822824c1d5e492bbc200a4bff3cc20
7
+ data.tar.gz: 1517ff9df9d457abab99ed385d3fb0c7d1e4a6bdf080a8c29ba5fe3a766d8024ae294f37bc8fe4c90142155914bba4bfd20cdf51108a590b33ba168d977cd27e
data/.rubocop.yml CHANGED
@@ -11,7 +11,7 @@ AllCops:
11
11
 
12
12
  Metrics/BlockLength:
13
13
  Enabled: true
14
- Max: 30
14
+ Max: 50
15
15
  Exclude:
16
16
  - lib/tasks/*.rake
17
17
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.6] - 2024-04-11 (Malifetes ben fetes)
4
+
5
+ - Add remover users task
6
+
7
+ ## [0.1.5] - 2024-02-08 (Pastissos voladors de colors)
8
+
9
+ - Fix homepage in rubygems.org
10
+ - Add organization id and name in spam csv
11
+
12
+ ## [0.1.4] - 2024-01-30 (Peus grans com gegants)
13
+
14
+ - Add users spam detector task
15
+
3
16
  ## [0.1.3] - 2023-06-23 (Tan iguals com especials)
4
17
 
5
18
  - Validate migrations task
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- decidim-cdtb (0.1.3)
4
+ decidim-cdtb (0.1.6)
5
5
  decidim (>= 0.26.2)
6
6
  rails (>= 6)
7
7
  ruby-progressbar
@@ -775,4 +775,4 @@ DEPENDENCIES
775
775
  sqlite3
776
776
 
777
777
  BUNDLED WITH
778
- 2.3.6
778
+ 2.4.22
data/README.md CHANGED
@@ -36,17 +36,6 @@ bin/rake cdtb:org_by_host_like[vila]
36
36
  host: localhost, time_zone: Madrid, locales: ca + [ca, es, oc], available authorizations: [postal_letter, members_picker_authorization_handler]
37
37
  ```
38
38
 
39
- ### Fix nicknames
40
-
41
- In a previous version than Decidim v0.25 a validation to the `Decidim::User.nickname` was added with a migration to fix existing nicknames. But the migration was only taking into acocunt managed (impersonated) users.
42
-
43
- This task iterates (with `find_each`) over all non managed users and nicknamizes the nickname.
44
-
45
- To execute the task run:
46
-
47
- ```
48
- bin/rake cdtb:fix_nicknames
49
- ```
50
39
 
51
40
  ### Anonymize production dump
52
41
 
@@ -76,6 +65,58 @@ To migrate from S3 to local storage, the identified steps will be:
76
65
  `bin/rake cache:clear`
77
66
  5. Restart the Rails server
78
67
 
68
+ ### Detect spam
69
+
70
+ To detect spam in Decidim.
71
+
72
+ #### Detect spam users
73
+ Detects users susceptible of being spammers. It can run on all organizations or be scoped to a single organization by passing the organization ID as the rake task parameter.
74
+
75
+ This rake task export a .csv with a list of all the searched users. A column indicates if each user is suspicious of being a spammer or not.
76
+ The columns in the CSV are: "ID, "Is suspicious?", "Name", "Email", "Nickname", "Personal URL", "About"
77
+
78
+ Examples:
79
+ `bin/rake cdtb:spam:users[org_id]` --> find users in organization with an id.
80
+ `bin/rake cdtb:spam:users` --> find all users in all organizations.
81
+
82
+ To set custom words in the rake, you can override it with an initalizer:
83
+
84
+ ```
85
+ Decidim::Cdtb.configure do |config|
86
+ config.spam_words = ENV["CDTB_SPAM_WORDS"]&.split(",")
87
+ end
88
+ ```
89
+
90
+ ### Users
91
+
92
+ Tasks related with users.
93
+
94
+ ### Fix nicknames
95
+
96
+ In a previous version than Decidim v0.25 a validation to the `Decidim::User.nickname` was added with a migration to fix existing nicknames. But the migration was only taking into account managed (impersonated) users.
97
+
98
+ This task iterates (with `find_each`) over all non managed users and nicknamizes the nickname.
99
+
100
+ To execute the task run:
101
+
102
+ ```
103
+ bin/rake cdtb:users:fix_nicknames
104
+ ```
105
+
106
+ #### Remove users
107
+
108
+ You can delete users through a CSV with the user ID. The purpose is to be able to eliminate potentially spammy users.
109
+
110
+ This task reports and hide the user's comments, blocks the user, and finally deletes the user.
111
+
112
+ The CSV will have a header and one column with the user ID.
113
+
114
+ To execute the task run:
115
+
116
+ ```
117
+ bundle exec rake cdtb:users:remove[spam_users.csv]
118
+ ```
119
+
79
120
  ### Upgrades:
80
121
 
81
122
  #### Upgrade modules
data/decidim-cdtb.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "CodiTramuntana's Decidim Toolbelt (cdtb)."
12
12
  spec.description = "A gem to help managing Decidim applications."
13
- spec.homepage = "http://github.com/CodiTramunana/cdtb"
13
+ spec.homepage = "https://github.com/CodiTramuntana/decidim-module-cdtb"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.7.5"
16
16
 
@@ -10,6 +10,10 @@ module Decidim
10
10
  # Workaround for https://stackoverflow.com/questions/72970170/upgrading-to-rails-6-1-6-1-causes-psychdisallowedclass-tried-to-load-unspecif
11
11
  Rails.application.config.active_record.use_yaml_unsafe_load = true
12
12
  end
13
+
14
+ config.after_initialize do
15
+ Decidim::Cdtb.config.spam_regexp = Regexp.union(Decidim::Cdtb.config.spam_words)
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module Decidim
6
+ module Cdtb
7
+ module Spam
8
+ # Detect spam behavior in users
9
+ #
10
+ class UserSpamDetector < ::Decidim::Cdtb::Task
11
+ # rubocop:disable Style/RedundantRegexpEscape
12
+ URL_REGEX = %r{(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|
13
+ www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|
14
+ (?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})}.freeze
15
+ # rubocop:enable Style/RedundantRegexpEscape
16
+
17
+ def initialize(organization = nil)
18
+ @organization = organization
19
+ progress_bar = { title: "Decidim::User" }
20
+ super("SPAM DETECTOR", progress_bar: progress_bar)
21
+ end
22
+
23
+ def prepare_execution(_ctx)
24
+ @users = if @organization.present?
25
+ Decidim::User.where(organization: @organization)
26
+ else
27
+ Decidim::User.all
28
+ end
29
+
30
+ @num_users = @users.count
31
+ log_task_info("Checking #{@num_users} users...")
32
+ end
33
+
34
+ def total_items
35
+ @num_users
36
+ end
37
+
38
+ # rubocop:disable Metrics/AbcSize
39
+ def do_execution(context)
40
+ progress_bar = context[:progress_bar]
41
+ CSV.open("spam_users.csv", "w") do |csv|
42
+ csv_headers = ["ID", "Is suspicious?", "Name", "Email", "Nickname", "Personal URL", "About",
43
+ "Organization ID", "Organization Name"]
44
+ csv << csv_headers
45
+
46
+ @users.find_each do |user|
47
+ suspicious = "NO"
48
+
49
+ if spam_user?(user)
50
+ suspicious = "YES"
51
+ @num_applied+= 1
52
+ end
53
+
54
+ csv << [user.id, suspicious, user.name, user.email, user.nickname, user.personal_url, user.about,
55
+ user.organization.id, user.organization.name]
56
+
57
+ progress_bar.increment
58
+ end
59
+ end
60
+ end
61
+ # rubocop:enable Metrics/AbcSize
62
+
63
+ def end_execution(_ctx)
64
+ if @num_applied.positive?
65
+ log_task_step("#{@num_applied} suspicious users")
66
+ log_task_step("Suspicious users list exported to spam_users.csv")
67
+ else
68
+ log_task_step("There are not suspicious users!!")
69
+ end
70
+ end
71
+
72
+ def spam_user?(user)
73
+ has_spam_word?(user) || has_spam_url?(user)
74
+ end
75
+
76
+ private
77
+
78
+ def has_spam_word?(user)
79
+ [user.name, user.about, user.nickname,
80
+ user.personal_url, user.about].compact.join("||").match?(Decidim::Cdtb.config.spam_regexp)
81
+ end
82
+
83
+ def has_spam_url?(user)
84
+ !!(user&.about =~ URL_REGEX || user.name =~ URL_REGEX)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -3,7 +3,9 @@
3
3
  require "decidim/cdtb/tasks_utils"
4
4
  require "decidim/cdtb/task"
5
5
  require "decidim/cdtb/fixes/nickname_fixer"
6
+ require "decidim/cdtb/users/remover"
6
7
  require "decidim/cdtb/multitenants/org_by_host_like"
8
+ require "decidim/cdtb/spam/user_spam_detector"
7
9
  require "decidim/cdtb/storage/local_sharding"
8
10
  require "decidim/cdtb/storage/set_local_on_blobs"
9
11
  require "decidim/cdtb/upgrades/validate_migrations_task"
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Cdtb
5
+ module Users
6
+ # Remove Decidim::User's
7
+ #
8
+ class Remover < ::Decidim::Cdtb::Task
9
+ def initialize(csv_path)
10
+ @csv_path = csv_path
11
+ progress_bar = { title: "Decidim::User" }
12
+ super("USER REMOVER", progress_bar: progress_bar)
13
+ end
14
+
15
+ def prepare_execution(_ctx); end
16
+
17
+ def total_items
18
+ File.open(@csv_path).readlines.size - 1
19
+ end
20
+
21
+ def do_execution(context)
22
+ progress_bar = context[:progress_bar]
23
+
24
+ CSV.foreach(@csv_path, headers: true, col_sep: ",") do |row|
25
+ user = Decidim::User.find_by(id: row[0])
26
+ next unless user.present?
27
+
28
+ reporter_user = Decidim::User.find_by(email: "support@coditramuntana.com",
29
+ organization: user.organization)
30
+ comments = Decidim::Comments::Comment.where(decidim_author_id: user.id)
31
+ manage_comments(comments, reporter_user) unless comments.empty?
32
+ destroy_user(user) if block_user(user, reporter_user)
33
+ progress_bar.increment
34
+ end
35
+ end
36
+
37
+ def end_execution(_ctx)
38
+ log_task_step("#{@num_applied} users removed")
39
+ end
40
+
41
+ private
42
+
43
+ def manage_comments(comments, reporter_user)
44
+ comments.find_each do |comment|
45
+ report_comment(comment, reporter_user)
46
+ hide_comment(comment, reporter_user)
47
+ end
48
+ end
49
+
50
+ def block_user(user, reporter_user)
51
+ params = {
52
+ user_id: user.id,
53
+ justification: "Confirmed spam suspicious"
54
+ }
55
+
56
+ form = Decidim::Admin::BlockUserForm.from_params(params).with_context(
57
+ {
58
+ current_organization: user.organization,
59
+ current_user: reporter_user
60
+ }
61
+ )
62
+
63
+ Decidim::Admin::BlockUser.call(form) do
64
+ on(:ok) do
65
+ puts "OK: User #{user.id} blocked"
66
+ return true
67
+ end
68
+
69
+ on(:invalid) do
70
+ puts "ERROR: User #{user.id} not blocked"
71
+ return false
72
+ end
73
+ end
74
+ end
75
+
76
+ def destroy_user(user)
77
+ params = {
78
+ delete_reason: "Confirmed spam suspicious"
79
+ }
80
+
81
+ form = Decidim::DeleteAccountForm.from_params(params)
82
+
83
+ Decidim::DestroyAccount.call(user, form) do
84
+ on(:ok) do
85
+ puts "OK: User #{user.id} removed"
86
+ end
87
+
88
+ on(:invalid) do
89
+ puts "ERROR: User #{user.id} not removed"
90
+ end
91
+ end
92
+ end
93
+
94
+ def report_comment(comment, reporter_user)
95
+ params = {
96
+ reason: "spam",
97
+ details: "Spam message"
98
+ }
99
+
100
+ form = Decidim::ReportForm.from_params(params)
101
+
102
+ CreateReport.call(form, comment, reporter_user) do
103
+ on(:ok) do
104
+ puts "OK: Comment #{comment.id} of User #{user.id} reported"
105
+ end
106
+
107
+ on(:invalid) do
108
+ puts "ERROR: Comment #{comment.id} of User #{user.id} not reported"
109
+ end
110
+ end
111
+ end
112
+
113
+ def hide_comment(comment, reporter_user)
114
+ Admin::HideResource.call(comment, reporter_user) do
115
+ on(:ok) do
116
+ puts "OK: Comment #{comment.id} of User #{user.id} hided"
117
+ end
118
+
119
+ on(:invalid) do
120
+ puts "ERROR: Comment #{comment.id} of User #{user.id} not hided"
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Cdtb
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.6"
6
6
  DECIDIM_MIN_VERSION = ">= 0.26.2"
7
7
  end
8
8
  end
data/lib/decidim/cdtb.rb CHANGED
@@ -5,7 +5,14 @@ require_relative "cdtb/engine"
5
5
  require_relative "cdtb/tasks"
6
6
 
7
7
  module Decidim
8
+ # Cdtb configuration
8
9
  module Cdtb
10
+ include ActiveSupport::Configurable
11
+
9
12
  class Error < StandardError; end
13
+
14
+ config_accessor :spam_words do
15
+ %w[viagra sex game free crypto crack xxx luck girls vip download]
16
+ end
10
17
  end
11
18
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :cdtb do
4
+ namespace :spam do
5
+ desc "Show a list with users suspected of spam"
6
+ task :users, %i[org_id] => :environment do |_task, args|
7
+ organization = args.org_id.present? ? Decidim::Organization.find(args.org_id) : nil
8
+
9
+ detector = ::Decidim::Cdtb::Spam::UserSpamDetector.new(organization)
10
+ detector.execute!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/cdtb/tasks"
4
+
5
+ namespace :cdtb do
6
+ namespace :users do
7
+ desc <<~EODESC
8
+ Fix Decidim::User's nicknames.
9
+ EODESC
10
+ task fix_nicknames: [:environment] do
11
+ fixer= ::Decidim::Cdtb::Fixes::NicknameFixer.new
12
+ fixer.execute!
13
+ end
14
+
15
+ desc <<~EODESC
16
+ Remove Decidim::User's by IDs in a CSV.
17
+ EODESC
18
+ task :remove, %i[csv_file] => [:environment] do |_taks, args|
19
+ service = ::Decidim::Cdtb::Users::Remover.new(args.csv_file)
20
+ service.execute!
21
+ end
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-cdtb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Valls
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-10 00:00:00.000000000 Z
11
+ date: 2024-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: decidim
@@ -105,6 +105,7 @@ files:
105
105
  - lib/decidim/cdtb/engine.rb
106
106
  - lib/decidim/cdtb/fixes/nickname_fixer.rb
107
107
  - lib/decidim/cdtb/multitenants/org_by_host_like.rb
108
+ - lib/decidim/cdtb/spam/user_spam_detector.rb
108
109
  - lib/decidim/cdtb/storage/local_sharding.rb
109
110
  - lib/decidim/cdtb/storage/set_local_on_blobs.rb
110
111
  - lib/decidim/cdtb/task.rb
@@ -113,23 +114,25 @@ files:
113
114
  - lib/decidim/cdtb/upgrades/install_gem_migrations_step.rb
114
115
  - lib/decidim/cdtb/upgrades/upgrade_modules_task.rb
115
116
  - lib/decidim/cdtb/upgrades/validate_migrations_task.rb
117
+ - lib/decidim/cdtb/users/remover.rb
116
118
  - lib/decidim/cdtb/version.rb
117
119
  - lib/generators/cdtb/USAGE
118
120
  - lib/generators/cdtb/templates/validate_migrations.yml
119
121
  - lib/generators/cdtb/validate_migrations_ci_generator.rb
120
122
  - lib/tasks/anonymize.rake
121
- - lib/tasks/cdtb.rake
122
123
  - lib/tasks/multitenants.rake
124
+ - lib/tasks/spam.rake
123
125
  - lib/tasks/storage.rake
124
126
  - lib/tasks/upgrade.rake
127
+ - lib/tasks/users.rake
125
128
  - sig/decidim/cdtb.rbs
126
- homepage: http://github.com/CodiTramunana/cdtb
129
+ homepage: https://github.com/CodiTramuntana/decidim-module-cdtb
127
130
  licenses:
128
131
  - MIT
129
132
  metadata:
130
- homepage_uri: http://github.com/CodiTramunana/cdtb
131
- source_code_uri: http://github.com/CodiTramunana/cdtb
132
- changelog_uri: http://github.com/CodiTramunana/cdtb/CHANGELOG.md
133
+ homepage_uri: https://github.com/CodiTramuntana/decidim-module-cdtb
134
+ source_code_uri: https://github.com/CodiTramuntana/decidim-module-cdtb
135
+ changelog_uri: https://github.com/CodiTramuntana/decidim-module-cdtb/CHANGELOG.md
133
136
  post_install_message:
134
137
  rdoc_options: []
135
138
  require_paths:
data/lib/tasks/cdtb.rake DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "decidim/cdtb/tasks"
4
-
5
- namespace :cdtb do
6
- desc <<~EODESC
7
- Fix Decidim::User's nicknames.
8
- EODESC
9
- task fix_nicknames: [:environment] do
10
- fixer= ::Decidim::Cdtb::Fixes::NicknameFixer.new
11
- fixer.execute!
12
- end
13
- end