decidim-cdtb 0.2.1 → 0.4.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: 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