decidim-cdtb 0.2.1 → 0.4.0

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: faf1cb50d2671115898ec0bb910f90643f6cddd804cc72ea60a7282613b6e28b
4
- data.tar.gz: 43fda83541900039ecd2496260d9e9bb2f249447e296c359a363d01470a9508c
3
+ metadata.gz: 153977aa97421818ceebb2f5bd934c01df29717da6b03cec2d3e596868cf482b
4
+ data.tar.gz: 4b0f14017084367cb8665ffcca4fe4ea9c6db70667cdf9d253366cd667819991
5
5
  SHA512:
6
- metadata.gz: 3da6dc75b25cb6d7eaea5b5a27bdbcce3772f57e066b37bf3b3fb1b7fd7e6c19417e5fb7288ab433d5f15e4eab7d78dcf63d3518e60f8f64e6937ae576ca3729
7
- data.tar.gz: 1d1fc82dee68f7d3d72ffc8f8eea7376e4a97a42350725ace3c9d0e1815b86bbd020a2e360dccd2f9cfd61fe6723a78bb365d56a0cab60081ac3aea43c60766a
6
+ metadata.gz: a7c0f4ec00c7d921a2182de07d3601f7c99027ebdcbda6550d7d19007d98051b5c0e1864da1aa45a377b0b5206146032fc42b19338ad5857c501ba2840451df1
7
+ data.tar.gz: ee1d931e38468fadd1cfbc0b0e1f1504358f37da6a99f8c46ba6666989cb0a59c644d8ac6c5d4a63e24cca812676ce8f418637332f2488aee774f4fa0e2f8ff7
data/.rubocop.yml CHANGED
@@ -14,6 +14,7 @@ Metrics/BlockLength:
14
14
  Max: 50
15
15
  Exclude:
16
16
  - lib/tasks/*.rake
17
+ - spec/**/*_spec.rb
17
18
 
18
19
  Metrics/MethodLength:
19
20
  CountComments: false
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.2.1] - 2024-09-25 (patch)
3
+ ## [0.4.0] - 2025-02-10 (minor - Llefiscós però deliciós)
4
+
5
+ - Add task to move images to hero content block in participatory spaces
6
+ - Improve remove users task disabling and enabling email on moderations
7
+
8
+ ## [0.3.0] - 2024-12-24 (minor - L'artista de la pista)
9
+
10
+ - Fix YouTube embeds to Decidim v0.28 format in different places. Only YouTube is supported right now.
11
+ - Add task to add new content blocks in participatory spaces
12
+
13
+ ## [0.2.1] - 2024-09-25 (patch - Una idea sobre rodes)
4
14
 
5
15
  - Fix validate_migrations CI which requires Postgres service
6
16
 
data/Gemfile CHANGED
@@ -9,6 +9,7 @@ require_relative "lib/decidim/cdtb/version"
9
9
 
10
10
  # temporal solution while gems embrace new psych 4 (the default in Ruby 3.1) behavior.
11
11
  gem "psych", "< 4"
12
+ gem "uri", ">= 0.13.1"
12
13
 
13
14
  group :development, :test do
14
15
  gem "bootsnap", require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- decidim-cdtb (0.2.1)
4
+ decidim-cdtb (0.4.0)
5
5
  decidim (>= 0.27.0)
6
6
  rails (>= 6)
7
7
  ruby-progressbar
@@ -745,7 +745,7 @@ GEM
745
745
  concurrent-ruby (~> 1.0)
746
746
  uber (0.1.0)
747
747
  unicode-display_width (2.5.0)
748
- uri (0.13.0)
748
+ uri (0.13.1)
749
749
  valid_email2 (2.3.1)
750
750
  activemodel (>= 3.2)
751
751
  mail (~> 2.5)
@@ -805,6 +805,7 @@ DEPENDENCIES
805
805
  rspec (~> 3.0)
806
806
  rubocop
807
807
  sqlite3 (~> 1.4)
808
+ uri (>= 0.13.1)
808
809
 
809
810
  BUNDLED WITH
810
811
  2.3.6
data/README.md CHANGED
@@ -51,6 +51,21 @@ Available rake tasks:
51
51
  - `bin/rake cdtb:anonymize:system_admins` anonymizes system admins
52
52
  - `bin/rake cdtb:anonymize:paper_trail` anonymizes paper trails
53
53
 
54
+ ### Fix YouTube embeds for Decidim v0.28
55
+
56
+ Fixes YouTube embeds to Decidim v0.28 format in different places, which at the moment are:
57
+
58
+ - Decidim::Meetings::Meeting
59
+ - Decidim::Debates::Debate
60
+ - Decidim::Pages::Page
61
+ - Decidim::Assembly
62
+ - Decidim::ParticipatoryProcess
63
+
64
+ ```
65
+ bin/rake cdtb:embeds:fix_youtube
66
+ ```
67
+
68
+
54
69
  ### Migrate ActiveStorage service from S3 to local
55
70
 
56
71
  To migrate from S3 to local storage, the identified steps will be:
@@ -127,12 +142,100 @@ You can delete users through a CSV with the user ID and a reporter user mailer.
127
142
 
128
143
  This task reports and hide the user's comments, blocks the user, and finally deletes the user.
129
144
 
130
- The CSV will have a header and one column with the user ID.
145
+ The CSV will have a header and one column with the user ID and must be separated by ",".
146
+
147
+ To execute the task run:
148
+
149
+ ```
150
+ bundle exec rake cdtb:users:remove[spam_users.csv,reporter_user@example.org]
151
+ ```
152
+
153
+ ### Participatory Spaces
154
+
155
+ #### Add content blocks
156
+
157
+ You can add content blocks to a participatory spaces with the content block name (manifest_name).
158
+ This rake task affects spaces in all organizations.
159
+
160
+ Content block manifest names list:
161
+
162
+ ```
163
+ basic_only_text
164
+ image_text_cta
165
+ metadata
166
+ hero
167
+ participatory_processes
168
+ html_2
169
+ main_data
170
+ title
171
+ cta
172
+ highlighted_proposals
173
+ how_to_participate
174
+ html_1
175
+ related_documents
176
+ stats
177
+ html
178
+ slider
179
+ footer_sub_hero
180
+ global_menu
181
+ sub_hero
182
+ highlighted_content_banner
183
+ highlighted_processes
184
+ highlighted_assemblies
185
+ highlighted_regulations
186
+ upcoming_meetings
187
+ extra_data
188
+ highlighted_meetings
189
+ highlighted_results
190
+ metrics
191
+ related_assemblies
192
+ announcement
193
+ social_networks_metadata
194
+ related_processes
195
+ highlighted_posts
196
+ last_activity
197
+ ```
198
+
199
+ Spaces supported:
200
+
201
+ - Decidim::ParticipatoryProcess
202
+ - Decidim::Assembly
203
+
204
+ To execute the task run:
205
+
206
+ ```
207
+ bundle exec rake cdtb:participatory_spaces:add_content_blocks[manifest_name]
208
+ ```
209
+
210
+ You can add multiple manifest names with this format:
211
+
212
+ ```
213
+ bundle exec rake cdtb:participatory_spaces:add_content_blocks[['manifest_name_one manifest_name_two']]
214
+ ```
215
+
216
+ Some examples
217
+ ```
218
+ bundle exec rake cdtb:participatory_spaces:add_content_blocks[extra_data]
219
+
220
+ bundle exec rake cdtb:participatory_spaces:add_content_blocks[['extra_data related_documents']]
221
+
222
+ ```
223
+
224
+ #### Move banner images to hero content block
225
+
226
+ In previous versions of Decidim (0.27 and previous) banner images are in participatory space configuration. Now, this image is in a content block but for old spaces are in configuration yet.
227
+
228
+ This task move the banner image to a hero content block.
229
+
230
+ Spaces supported:
231
+
232
+ - Decidim::ParticipatoryProcess
233
+ - Decidim::Assembly
131
234
 
132
235
  To execute the task run:
133
236
 
134
237
  ```
135
- bundle exec rake cdtb:users:remove[spam_users.csv, reporter_user@example.org]
238
+ bundle exec rake cdtb:participatory_spaces:move_images_to_content_block
136
239
  ```
137
240
 
138
241
  ### Upgrades:
@@ -3,26 +3,49 @@
3
3
  unless ENV["CDTB_RACK_ATTACK_DISABLED"].to_i.positive? || %w[development test].include?(Rails.env)
4
4
  require "rack/attack"
5
5
 
6
- limit= ENV.fetch("RACK_ATTACK_THROTTLE_LIMIT", 30)
7
- period= ENV.fetch("RACK_ATTACK_THROTTLE_PERIOD", 60)
8
- Rails.logger.info("Configuring Rack::Attack.throttle with limit: #{limit}, period: #{period}")
9
- Rack::Attack.throttle("requests by (forwarded) ip", limit: limit.to_i, period: period.to_i) do |request|
10
- # ignore requests to assets
11
- next if request.path.start_with?("/rails/active_storage")
12
-
6
+ def extract_ip(request)
13
7
  x_forwarded_for= request.get_header("HTTP_X_FORWARDED_FOR")
14
8
  Rails.logger.info { ">>>>>>>>>>>>>>>>>>>> X-Forwarded-For: #{x_forwarded_for}" }
15
9
  if x_forwarded_for.present?
16
- ip= x_forwarded_for.split(":").first
17
- ip
10
+ x_forwarded_for.split(":").first
11
+
18
12
  else
19
13
  request.ip
20
14
  end
21
15
  end
22
16
 
17
+ limit= ENV.fetch("RACK_ATTACK_THROTTLE_LIMIT", 30)
18
+ period= ENV.fetch("RACK_ATTACK_THROTTLE_PERIOD", 60)
19
+ Rails.logger.info("Configuring Rack::Attack.throttle with limit: #{limit}, period: #{period}")
20
+ Rack::Attack.throttle("requests by ip", limit: limit.to_i, period: period.to_i) do |request|
21
+ # ignore requests to assets
22
+ next if request.path.start_with?("/rails/active_storage")
23
+
24
+ extract_ip(request)
25
+ end
26
+
27
+ limit= ENV.fetch("RACK_ATTACK_THROTTLE_RANGE_LIMIT", 10)
28
+ period= ENV.fetch("RACK_ATTACK_THROTTLE_RANGE_PERIOD", 20)
29
+ Rails.logger.info("Configuring Rack::Attack.throttle with limits for IP Ranges: #{limit}, period: #{period}")
30
+ Rack::Attack.throttle("requests by ip range", limit: limit.to_i, period: period.to_i) do |request|
31
+ # ignore requests to assets
32
+ next if request.path.start_with?("/rails/active_storage")
33
+
34
+ ip= extract_ip(request)
35
+ # rubocop: disable Lint/UselessAssignment
36
+ range_32bit= ip.split(".")[0, 2]
37
+ # rubocop: enable Lint/UselessAssignment
38
+ end
39
+
40
+ Rack::Attack.blocklist("block all /.well-known/traffic-advice") do |request|
41
+ request.path.start_with?("/.well-known/traffic-advice")
42
+ end
43
+
23
44
  if ENV["RACK_ATTACK_BLOCKED_IPS"].present?
24
- ENV["RACK_ATTACK_BLOCKED_IPS"].split(",").each do |ip_or_subnet|
25
- Rack::Attack.blocklist_ip(ip_or_subnet)
45
+ blocked_ips_and_subnets= ENV["RACK_ATTACK_BLOCKED_IPS"].split(",")
46
+ Rack::Attack.blocklist("block all unaccepted IPs") do |request|
47
+ ip= extract_ip(request)
48
+ blocked_ips_and_subnets.any? { |ip_or_subnet| ip.start_with?(ip_or_subnet) }
26
49
  end
27
50
  end
28
51
  end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require "decidim"
4
+ # require "decidim/assembly"
5
+ # require "decidim/participatory_process"
6
+ # require "decidim/meetings/meeting"
7
+ # require "decidim/debates/debate"
8
+ # require "decidim/pages/page"
9
+
10
+ module Decidim
11
+ module Cdtb
12
+ module Fixes
13
+ # Fixes YouTube embeds to Decidim v0.28 format in PROCESSED_MODELS.
14
+ # Only YouTube is supported right now.
15
+ class YouTubeEmbedsFixer < ::Decidim::Cdtb::Task
16
+ PROCESSED_MODELS= {
17
+ "Decidim::Meetings::Meeting" => [:description],
18
+ "Decidim::Debates::Debate" => %i[description instructions],
19
+ "Decidim::Pages::Page" => [:body],
20
+ "Decidim::Assembly" => %i[short_description description],
21
+ "Decidim::ParticipatoryProcess" => %i[short_description description]
22
+ }.freeze
23
+
24
+ def initialize
25
+ progress_bar= { title: self.class.name }
26
+ super("FIX YOUTUBE EMBEDS", progress_bar: progress_bar)
27
+ end
28
+
29
+ attr_reader :num_fixed
30
+
31
+ def prepare_execution(_ctx = nil)
32
+ @num_fixed= @num_items= 0
33
+
34
+ PROCESSED_MODELS.each_key do |model_class|
35
+ @num_items+= model_class.constantize.count
36
+ end
37
+ log_task_info("Checking #{@num_items} models...")
38
+ end
39
+
40
+ def total_items
41
+ @num_items
42
+ end
43
+
44
+ def do_execution(context)
45
+ progress_bar= context[:progress_bar]
46
+
47
+ PROCESSED_MODELS.each_pair do |model_class_name, attribs|
48
+ log_task_step("Processing #{model_class_name.pluralize}")
49
+
50
+ model_class= model_class_name.constantize
51
+ model_class.find_each do |model|
52
+ Rails.logger.debug("Processing #{model_class_name}[#{model.id}]")
53
+
54
+ attribs.each do |attribute|
55
+ fix_embed(model, attribute)
56
+ end
57
+
58
+ @num_fixed+= 1 if model.changed?
59
+ model.save!(validate: false)
60
+ progress_bar.increment
61
+ end
62
+ end
63
+ end
64
+
65
+ def end_execution(_ctx)
66
+ log_task_step("#{@num_fixed} embeds fixed")
67
+ end
68
+
69
+ # --------------------------------------------------
70
+ private
71
+
72
+ # --------------------------------------------------
73
+
74
+ def fix_embed(model, attribute)
75
+ contents= model.send(attribute)
76
+ return if contents.blank?
77
+
78
+ contents.each_pair do |locale, content|
79
+ Rails.logger.debug "#{locale} => #{content}"
80
+ next if locale.to_s == "machine_translations"
81
+ next if content.blank?
82
+
83
+ fixes= fix_localized_embed(content)
84
+ contents[locale]= fixes.reverse.find { |fix| fix != false } if fixes.any?
85
+ end
86
+ end
87
+
88
+ # rubocop: disable Metrics/AbcSize
89
+ def fix_localized_embed(content)
90
+ parsed= Nokogiri::HTML(content)
91
+ divs_w_embed= parsed.css("div[class=editor-content-videoEmbed]")
92
+ Rails.logger.debug "=> #{divs_w_embed.size} => #{content}"
93
+
94
+ divs_w_embed.map do |div|
95
+ regexp_match= div["data-video-embed"].match(%r{https://www.youtube.com/embed/(?<yt_id>\w+)})
96
+ next unless regexp_match
97
+
98
+ Rails.logger.debug("EMBED:::: #{div.class} => #{div}")
99
+
100
+ yt_id= regexp_match["yt_id"]
101
+ div["data-video-embed"]= "https://www.youtube.com/watch?v=#{yt_id}"
102
+ iframe= div.css("iframe").first
103
+ iframe["src"]= "https://www.youtube-nocookie.com/embed/#{yt_id}?cc_load_policy=1&modestbranding=1"
104
+ fixed_div= div
105
+ Rails.logger.debug("FIXED TO: #{fixed_div.to_html}")
106
+ new_content= parsed.css("body").children.to_html
107
+ Rails.logger.debug("FIXED TO: #{new_content}")
108
+ new_content
109
+ end
110
+ end
111
+ # rubocop: enable Metrics/AbcSize
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/cdtb/participatory_spaces/manages_content_blocks"
4
+
5
+ module Decidim
6
+ module Cdtb
7
+ module ParticipatorySpaces
8
+ # Add content blocks to participatory spaces
9
+ class AddContentBlocks < ::Decidim::Cdtb::Task
10
+ include ::Decidim::Cdtb::ParticipatorySpaces::ManagesContentBlocks
11
+
12
+ def initialize(processed_models, content_block_names)
13
+ progress_bar= { title: self.class.name }
14
+ @processed_models = processed_models
15
+ @content_block_names = content_block_names
16
+ super("ADD CONTENT BLOCKS", progress_bar: progress_bar)
17
+ end
18
+
19
+ attr_reader :num_added
20
+
21
+ def prepare_execution(_ctx = nil)
22
+ @num_added= @num_items= 0
23
+
24
+ @processed_models.each do |model_name|
25
+ @num_items+= model_name.count
26
+ end
27
+ log_task_info("Adding content blocks in #{@num_items} spaces...")
28
+ end
29
+
30
+ def total_items
31
+ @num_items
32
+ end
33
+
34
+ # rubocop:disable Metrics/AbcSize
35
+ def do_execution(context)
36
+ progress_bar= context[:progress_bar]
37
+
38
+ @processed_models.each do |processed_model|
39
+ log_task_step("Processing #{processed_model}")
40
+
41
+ spaces = processed_model
42
+
43
+ @content_block_names.each do |content_block_name|
44
+ log_task_step("Adding #{content_block_name} content block")
45
+
46
+ spaces.find_each do |space|
47
+ current_content_blocks = current_space_content_blocks(scope_name(space), space.organization, space.id)
48
+
49
+ new_content_block = find_or_create_content_block(space, content_block_name)
50
+ if content_block_name == "extra_data" && space.instance_of?(Decidim::ParticipatoryProcess)
51
+ next if new_content_block.weight == 20
52
+
53
+ force_extra_data_content_block_weight!(content_block_name, current_content_blocks)
54
+ end
55
+
56
+ @num_added += 1
57
+ progress_bar.increment
58
+ end
59
+ end
60
+ end
61
+ end
62
+ # rubocop:enable Metrics/AbcSize
63
+
64
+ def end_execution(_ctx)
65
+ log_task_step("#{@num_added} content blocks added")
66
+ end
67
+
68
+ # +extra_data+ content block usually be down of hero image, therefore, it's weight is 20 and all others content blocks
69
+ # go one position down added 10
70
+ def force_extra_data_content_block_weight!(content_block_name, current_content_blocks)
71
+ extra_data_content_block = current_content_blocks.find_by(manifest_name: content_block_name)
72
+ extra_data_content_block.update(weight: 20)
73
+
74
+ current_content_blocks.each do |content_block|
75
+ # hero is usually the first content block
76
+ next if content_block == extra_data_content_block || content_block.manifest_name == "hero"
77
+
78
+ content_block.update(weight: content_block.weight + 10)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Cdtb
5
+ module ParticipatorySpaces
6
+ # Methods for use in participatory spaces tasks
7
+ module ManagesContentBlocks
8
+ # rubocop:disable Metrics/AbcSize
9
+ def find_or_create_content_block(space, content_block_name)
10
+ current_content_blocks = current_space_content_blocks(scope_name(space), space.organization, space.id)
11
+ exists_content_block = Decidim::ContentBlock.find_by(decidim_organization_id: space.organization.id,
12
+ scope_name: scope_name(space), manifest_name: content_block_name,
13
+ scoped_resource_id: space.id)
14
+
15
+ return exists_content_block if exists_content_block.present?
16
+
17
+ weight = (current_content_blocks.last.weight + 1) * 10
18
+ log_task_step("Adding #{content_block_name} to #{space.slug}[#{space.id}]")
19
+ Decidim::ContentBlock.create(
20
+ decidim_organization_id: space.organization.id,
21
+ weight: weight,
22
+ scope_name: scope_name(space),
23
+ scoped_resource_id: space.id,
24
+ manifest_name: content_block_name,
25
+ published_at: Time.current
26
+ )
27
+ end
28
+ # rubocop:enable Metrics/AbcSize
29
+
30
+ def update_content_block_image(content_block, image)
31
+ content_block.manifest.images.each do |image_config|
32
+ image_name = image_config[:name]
33
+
34
+ next if content_block.images_container.send(image_name).present?
35
+
36
+ content_block.images_container.send("#{image_name}=", image.blob)
37
+ content_block.save
38
+ end
39
+ end
40
+
41
+ def current_space_content_blocks(scope_name, organization, scoped_resource_id)
42
+ Decidim::ContentBlock.for_scope(scope_name, organization: organization).where(scoped_resource_id: scoped_resource_id)
43
+ end
44
+
45
+ def manifest_for(resource)
46
+ return resource.manifest if resource.is_a? Decidim::Participable
47
+ return resource.resource_manifest if resource.is_a? Decidim::Resourceable
48
+ end
49
+
50
+ def scope_name(space)
51
+ manifest_for(space).content_blocks_scope_name
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/cdtb/participatory_spaces/manages_content_blocks"
4
+
5
+ module Decidim
6
+ module Cdtb
7
+ module ParticipatorySpaces
8
+ # Move images to content block for participatory spaces
9
+ class MoveImagesToContentBlock < ::Decidim::Cdtb::Task
10
+ include ::Decidim::Cdtb::ParticipatorySpaces::ManagesContentBlocks
11
+
12
+ def initialize(processed_models)
13
+ progress_bar= { title: self.class.name }
14
+ @processed_models = processed_models
15
+ super("MOVING IMAGES...", progress_bar: progress_bar)
16
+ end
17
+
18
+ attr_reader :num_added
19
+
20
+ def prepare_execution(_ctx = nil)
21
+ @num_added= @num_items= 0
22
+
23
+ @processed_models.each do |model_name|
24
+ @num_items+= model_name.count
25
+ end
26
+ log_task_info("Moving images to content block in #{@num_items} spaces...")
27
+ end
28
+
29
+ def total_items
30
+ @num_items
31
+ end
32
+
33
+ def do_execution(context)
34
+ progress_bar= context[:progress_bar]
35
+
36
+ @processed_models.each do |processed_model|
37
+ log_task_step("Processing #{processed_model}")
38
+
39
+ spaces = processed_model
40
+
41
+ spaces.find_each do |space|
42
+ image_content_block = find_or_create_content_block(space, "hero")
43
+
44
+ next if image_content_block.images.present?
45
+
46
+ update_content_block_image(image_content_block, space.banner_image)
47
+
48
+ @num_added += 1
49
+ progress_bar.increment
50
+ end
51
+ end
52
+ end
53
+
54
+ def end_execution(_ctx)
55
+ log_task_step("#{@num_added} content blocks added")
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -3,8 +3,11 @@
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/fixes/you_tube_embeds_fixer"
6
7
  require "decidim/cdtb/users/remover"
7
8
  require "decidim/cdtb/multitenants/org_by_host_like"
9
+ require "decidim/cdtb/participatory_spaces/add_content_blocks"
10
+ require "decidim/cdtb/participatory_spaces/move_images_to_content_block"
8
11
  require "decidim/cdtb/spam/user_spam_detector"
9
12
  require "decidim/cdtb/storage/local_sharding"
10
13
  require "decidim/cdtb/storage/set_local_on_blobs"
@@ -20,9 +20,14 @@ module Decidim
20
20
  File.open(@csv_path).readlines.size - 1
21
21
  end
22
22
 
23
+ # rubocop:disable Metrics/AbcSize
23
24
  def do_execution(context)
24
25
  progress_bar = context[:progress_bar]
25
26
 
27
+ users_with_email_on_moderations = Decidim::User.where(email_on_moderations: true)
28
+
29
+ disable_email_moderations(users_with_email_on_moderations)
30
+
26
31
  CSV.foreach(@csv_path, headers: true, col_sep: ",") do |row|
27
32
  user = Decidim::User.find_by(id: row[0])
28
33
  next unless user.present?
@@ -34,7 +39,10 @@ module Decidim
34
39
  destroy_user(user) if block_user(user, reporter_user)
35
40
  progress_bar.increment
36
41
  end
42
+ ensure
43
+ enable_email_moderations(users_with_email_on_moderations)
37
44
  end
45
+ # rubocop:enable Metrics/AbcSize
38
46
 
39
47
  def end_execution(_ctx)
40
48
  log_task_step("#{@num_applied} users removed")
@@ -42,6 +50,24 @@ module Decidim
42
50
 
43
51
  private
44
52
 
53
+ def disable_email_moderations(users)
54
+ log_task_step("Disabling email on moderations...")
55
+
56
+ users.find_each do |user|
57
+ user.email_on_moderations = false
58
+ user.save(validate: false)
59
+ end
60
+ end
61
+
62
+ def enable_email_moderations(users)
63
+ log_task_step("Enabling email on moderations...")
64
+
65
+ users.find_each do |user|
66
+ user.email_on_moderations = true
67
+ user.save(validate: false)
68
+ end
69
+ end
70
+
45
71
  def manage_comments(comments, user, reporter_user)
46
72
  comments.find_each do |comment|
47
73
  report_comment(comment, user, reporter_user)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Cdtb
5
- VERSION = "0.2.1"
5
+ VERSION = "0.4.0"
6
6
  DECIDIM_MIN_VERSION = ">= 0.27.0"
7
7
  end
8
8
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/version"
4
+ require "decidim/cdtb/tasks"
5
+
6
+ namespace :cdtb do
7
+ namespace :embeds do
8
+ desc <<~EODESC
9
+ Fix YouTube embeds to Decidim v0.28 format.
10
+ Only youtube is supported right now.
11
+ EODESC
12
+ task fix_youtube: [:environment] do
13
+ unless Decidim.version >= "0.28"
14
+ puts "This command is only compatible with Decidim v0.28 or higher"
15
+ exit(-1)
16
+ end
17
+
18
+ fixer= ::Decidim::Cdtb::Fixes::YouTubeEmbedsFixer.new
19
+ fixer.execute!
20
+ end
21
+ end
22
+ end
data/lib/tasks/logs.rake CHANGED
@@ -2,15 +2,117 @@
2
2
 
3
3
  namespace :cdtb do
4
4
  namespace :logs do
5
- desc "Analize logs in Rails format. Counts the number of requests for each IP in the logs. Accepts a logfile param, it must be in log/."
5
+ desc "Analize logs in Rails format. Counts the number of requests for each IP in the logs. Accepts a log path param."
6
6
  task :num_rq_per_ip, [:logfile] do |_task, args|
7
- logfile= args.logfile || "development.log"
7
+ file_path= args.logfile || "log/production.log"
8
8
 
9
- file_path= "log/#{logfile}"
10
9
  first_cmd= "grep Started"
11
10
  piped_cmds= [%(grep " for "), "cut -d ' ' -f13", "sort", "uniq -c", "sort"].join(" | ")
12
- puts "Running: `#{first_cmd} #{file_path} | #{piped_cmds}`"
13
- puts `#{first_cmd} #{file_path} | #{piped_cmds}`
11
+ cmd= "#{first_cmd} #{file_path} | #{piped_cmds}"
12
+
13
+ puts "Running: `#{cmd}`"
14
+ puts `#{cmd}`
15
+ end
16
+
17
+ desc "Analize logs in Rails format. Counts the number of requests for each IP range in the logs. Accepts a log path param."
18
+ task :num_rq_per_ip_range, [:logfile] do |_task, args|
19
+ file_path= args.logfile || "log/production.log"
20
+
21
+ first_cmd= "grep Started"
22
+ piped_cmds= [
23
+ %(grep " for "),
24
+ # take the IP
25
+ "cut -d ' ' -f13",
26
+ # trim blank spaces
27
+ "awk '{$1=$1;print}'",
28
+ # range: only the first 2 blocks of the IP
29
+ "cut -d '.' -f1,2",
30
+ "sort",
31
+ "uniq -c",
32
+ "sort"
33
+ ].join(" | ")
34
+ cmd= "#{first_cmd} #{file_path} | #{piped_cmds}"
35
+
36
+ puts "Running: `#{cmd}`"
37
+ puts `#{cmd}`
38
+ end
39
+
40
+ desc 'Returns the duration, the order in the logs, and the timestamp of each "Completed" trace.'
41
+ task :slow_rq, [:logfile] do |_task, args|
42
+ # Based on the follwoing example execution:
43
+ # grep -e "Completed 200 OK in" log/development.log | ruby logparser.rb | sort
44
+
45
+ file_path= args.logfile || "log/production.log"
46
+
47
+ idx= 0
48
+ File.open(file_path).each_line do |line|
49
+ idx += 1
50
+ next unless line.include?("Completed 200 OK in")
51
+
52
+ split= line.split("Completed 200 OK in")
53
+ second_part= split.last.strip
54
+ words= second_part.split
55
+ response_duration= words.first
56
+ puts "#{response_duration.rjust(7, "0")}, #{idx}, #{line[4, 22]}"
57
+ end
58
+ end
59
+
60
+ desc "Most requested paths. Accepts a log path param, and an only_path to ignore the query part of the URL."
61
+ task :most_rq_paths, [:logfile, :only_path] do |_task, args|
62
+ file_path= args.logfile || "log/production.log"
63
+
64
+ first_cmd= "grep Started"
65
+ piped_cmds= ["cut -d ' ' -f11"]
66
+ piped_cmds << "cut -d '?' -f 1" if args.only_path == "only_path"
67
+ piped_cmds+= ["sort", "uniq -c", "sort"]
68
+ cmd= "#{first_cmd} #{file_path} | #{piped_cmds.join(" | ")}"
69
+
70
+ puts "Running: `#{cmd}`"
71
+ puts `#{cmd}`
72
+ end
73
+
74
+ desc "Analizes output from num_rq_per_ip. Finds the country from each IP in the log file. Accepts a log path param."
75
+ task :geolocate_ips, [:logfile] do |_task, args|
76
+ file_path= args.logfile || "log/num_rq_per_ip.log"
77
+
78
+ cmd= [
79
+ # strip spaces
80
+ "awk '{$1=$1;print}' #{file_path}",
81
+ "cut -d ' ' -f2",
82
+ "sort"
83
+ ].join(" | ")
84
+
85
+ cmd_out= `#{cmd}`
86
+ cmd_out.each_line do |ip|
87
+ ip= ip.strip
88
+ locations= Geocoder.search(ip)
89
+ location_rs= locations.first
90
+ country= parse_nominatim_result(location_rs) || parse_ipinfoio_result(location_rs) || "N/F"
91
+ puts "#{ip},#{country}"
92
+ end
93
+ end
94
+
95
+ def parse_nominatim_result(result)
96
+ result&.dig("address", "country")
97
+ end
98
+
99
+ def parse_ipinfoio_result(result)
100
+ result&.dig("country")
101
+ end
102
+
103
+ desc "Lists from the output of geolocated_ips. Finds the country from each IP in the csv file. Accepts a file path param."
104
+ task :bannable_ips, [:path, :countries] do |_task, args|
105
+ file_path= args.path || "tmp/geolocated_ips.csv"
106
+ countries= args.countries || %w[FR GB IT PT]
107
+
108
+ cmd= ["grep -v ES #{file_path}"]
109
+ countries.each do |country_iso|
110
+ cmd << "grep -v #{country_iso}"
111
+ end
112
+ cmd << "cut -d ',' -f1"
113
+ cmd << "sort"
114
+
115
+ puts `#{cmd.join(" | ")}`
14
116
  end
15
117
  end
16
118
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/version"
4
+ require "decidim/cdtb/tasks"
5
+
6
+ namespace :cdtb do
7
+ namespace :participatory_spaces do
8
+ desc <<~EODESC
9
+ Add content blocks to a participatory processes
10
+ EODESC
11
+ task :add_content_blocks, [:content_block_names] => :environment do |_task, args|
12
+ unless Decidim.version >= "0.28"
13
+ puts "This command is only compatible with Decidim v0.28 or higher"
14
+ exit(-1)
15
+ end
16
+
17
+ content_block_names = args[:content_block_names].split
18
+
19
+ puts "\n Select participatory spaces you want to add the content blocks: #{content_block_names}"
20
+ puts "\n 1. Decidim::ParticipatoryProcess"
21
+ puts "\n 2. Decidim::Assembly"
22
+ puts "\n 3. All"
23
+
24
+ selected_option = $stdin.gets.chomp
25
+ puts selected_option
26
+
27
+ case selected_option
28
+ when "1"
29
+ processed_models = [
30
+ Decidim::ParticipatoryProcess
31
+ ].freeze
32
+ when "2"
33
+ processed_models = [
34
+ Decidim::Assembly
35
+ ].freeze
36
+ when "3"
37
+ processed_models = [
38
+ Decidim::ParticipatoryProcess,
39
+ Decidim::Assembly
40
+ ].freeze
41
+ else
42
+ return "Please, select an option"
43
+ end
44
+
45
+ adder = ::Decidim::Cdtb::ParticipatorySpaces::AddContentBlocks.new(processed_models, content_block_names)
46
+ adder.execute!
47
+ end
48
+
49
+ desc <<~EODESC
50
+ Move images to content block for the participatory spaces
51
+ EODESC
52
+ task move_images_to_content_block: :environment do
53
+ unless Decidim.version >= "0.28"
54
+ puts "This command is only compatible with Decidim v0.28 or higher"
55
+ exit(-1)
56
+ end
57
+
58
+ puts "\n Select participatory spaces you want to move the images"
59
+ puts "\n 1. Decidim::ParticipatoryProcess"
60
+ puts "\n 2. Decidim::Assembly"
61
+ puts "\n 3. All"
62
+
63
+ selected_option = $stdin.gets.chomp
64
+ puts selected_option
65
+
66
+ case selected_option
67
+ when "1"
68
+ processed_models = [
69
+ Decidim::ParticipatoryProcess
70
+ ].freeze
71
+ when "2"
72
+ processed_models = [
73
+ Decidim::Assembly
74
+ ].freeze
75
+ when "3"
76
+ processed_models = [
77
+ Decidim::ParticipatoryProcess,
78
+ Decidim::Assembly
79
+ ].freeze
80
+ else
81
+ return "Please, select an option"
82
+ end
83
+
84
+ adder = ::Decidim::Cdtb::ParticipatorySpaces::MoveImagesToContentBlock.new(processed_models)
85
+ adder.execute!
86
+ end
87
+ end
88
+ 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.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Valls
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-27 00:00:00.000000000 Z
11
+ date: 2025-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: decidim
@@ -105,7 +105,11 @@ files:
105
105
  - lib/decidim/cdtb.rb
106
106
  - lib/decidim/cdtb/engine.rb
107
107
  - lib/decidim/cdtb/fixes/nickname_fixer.rb
108
+ - lib/decidim/cdtb/fixes/you_tube_embeds_fixer.rb
108
109
  - lib/decidim/cdtb/multitenants/org_by_host_like.rb
110
+ - lib/decidim/cdtb/participatory_spaces/add_content_blocks.rb
111
+ - lib/decidim/cdtb/participatory_spaces/manages_content_blocks.rb
112
+ - lib/decidim/cdtb/participatory_spaces/move_images_to_content_block.rb
109
113
  - lib/decidim/cdtb/spam/user_spam_detector.rb
110
114
  - lib/decidim/cdtb/storage/local_sharding.rb
111
115
  - lib/decidim/cdtb/storage/set_local_on_blobs.rb
@@ -122,8 +126,10 @@ files:
122
126
  - lib/generators/cdtb/validate_migrations_ci_generator.rb
123
127
  - lib/tasks/anonymize.rake
124
128
  - lib/tasks/census.rake
129
+ - lib/tasks/fix_youtube_embeds.rake
125
130
  - lib/tasks/logs.rake
126
131
  - lib/tasks/multitenants.rake
132
+ - lib/tasks/participatory_spaces.rake
127
133
  - lib/tasks/spam.rake
128
134
  - lib/tasks/storage.rake
129
135
  - lib/tasks/upgrade.rake