decidim-core 0.28.2 → 0.28.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/address/online.erb +2 -2
  3. data/app/cells/decidim/address_cell.rb +4 -0
  4. data/app/cells/decidim/card_g/show.erb +1 -1
  5. data/app/cells/decidim/card_g_cell.rb +5 -2
  6. data/app/cells/decidim/card_l/image.erb +2 -2
  7. data/app/cells/decidim/card_l_cell.rb +5 -2
  8. data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
  9. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  10. data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +2 -2
  11. data/app/commands/decidim/create_omniauth_registration.rb +10 -4
  12. data/app/controllers/concerns/decidim/devise_controllers.rb +1 -0
  13. data/app/controllers/concerns/decidim/paginable.rb +1 -1
  14. data/app/controllers/decidim/application_controller.rb +1 -0
  15. data/app/helpers/decidim/paginate_helper.rb +3 -5
  16. data/app/models/decidim/attachment.rb +3 -3
  17. data/app/models/decidim/component.rb +4 -1
  18. data/app/models/decidim/content_block.rb +2 -2
  19. data/app/models/decidim/user.rb +12 -12
  20. data/app/packs/src/decidim/input_character_counter.js +1 -1
  21. data/app/packs/stylesheets/decidim/_dropdown.scss +9 -9
  22. data/app/packs/stylesheets/decidim/_forms.scss +4 -4
  23. data/app/packs/stylesheets/decidim/_tooltip.scss +10 -10
  24. data/app/packs/stylesheets/decidim/editor.scss +1 -1
  25. data/app/services/decidim/download_your_data_exporter.rb +36 -25
  26. data/app/services/decidim/open_data_exporter.rb +8 -7
  27. data/app/views/decidim/manifests/show.json.erb +4 -4
  28. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  29. data/app/views/layouts/decidim/footer/_main_intro.html.erb +1 -1
  30. data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +1 -1
  31. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
  32. data/config/locales/ca.yml +3 -3
  33. data/config/locales/cs.yml +2 -0
  34. data/config/locales/fi-plain.yml +3 -3
  35. data/config/locales/fi.yml +28 -28
  36. data/config/locales/is-IS.yml +3 -0
  37. data/config/locales/sv.yml +124 -87
  38. data/db/migrate/20181025082245_add_timestamps_to_components.rb +5 -1
  39. data/decidim-core.gemspec +0 -1
  40. data/lib/decidim/asset_router/storage.rb +214 -11
  41. data/lib/decidim/core/engine.rb +8 -0
  42. data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +1 -1
  43. data/lib/decidim/core/test/shared_examples/follows_examples.rb +8 -3
  44. data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +5 -5
  45. data/lib/decidim/core/version.rb +1 -1
  46. data/lib/decidim/seven_zip_wrapper.rb +29 -0
  47. data/lib/tasks/upgrade/decidim_fix_categorization.rake +101 -1
  48. metadata +7 -21
  49. data/app/services/decidim/zip_stream/writer.rb +0 -39
@@ -6,6 +6,23 @@ module Decidim
6
6
  # saved through ActiveStorage. This handles the different cases for routing
7
7
  # to the remote routes when using an assets CDN or to local routes when
8
8
  # using the local disk storage driver.
9
+ #
10
+ # Note that when the assets are stored in a remote storage service, such as
11
+ # Amazon S3, Google Cloud Storage or Azure Storage, this generates the asset
12
+ # URL directly to the storage service itself bypassing the Rails server and
13
+ # saving CPU time from serving the asset redirect requests. This causes a
14
+ # significant performance improvement on pages that display a lot of images.
15
+ # It will also produce a less significant performance improvement when using
16
+ # the local disk storage because in this situation, the images are served
17
+ # using one request instead of two when served directly from the storage
18
+ # service rather than through the asset redirect URL.
19
+ #
20
+ # When implementing changes to the logic, please keep the remote storage
21
+ # options and performance implications in mind because the specs for this
22
+ # utility do not cover the remote storage options because the extra
23
+ # configuration needed to test, the service itself needed for testing and
24
+ # the extra dependency overhead for adding these remote storage gems when
25
+ # they are not needed.
9
26
  class Storage
10
27
  # Initializes the router.
11
28
  #
@@ -13,25 +30,36 @@ module Decidim
13
30
  # to
14
31
  def initialize(asset)
15
32
  @asset = asset
33
+ @blob =
34
+ case asset
35
+ when ActiveStorage::Blob
36
+ asset
37
+ else
38
+ asset&.blob
39
+ end
16
40
  end
17
41
 
18
42
  # Generates the correct URL to the asset with the provided options.
19
43
  #
20
44
  # @param options The options for the URL that are the normal route options
21
45
  # Rails route helpers accept
46
+ # @return [String] The URL of the asset
22
47
  def url(**options)
23
- if asset.is_a? ActiveStorage::Attached
24
- routes.rails_blob_url(asset.blob, **default_options.merge(options))
25
- elsif asset.is_a? ActiveStorage::Blob
26
- routes.rails_blob_url(asset, **default_options.merge(options))
27
- else
48
+ case asset
49
+ when ActiveStorage::Attached
50
+ ensure_current_host(asset.record, **options)
51
+ blob_url(**options)
52
+ when ActiveStorage::Blob
53
+ blob_url(**options)
54
+ else # ActiveStorage::VariantWithRecord, ActiveStorage::Variant
55
+ ensure_current_host(nil, **options)
28
56
  representation_url(**options)
29
57
  end
30
58
  end
31
59
 
32
60
  private
33
61
 
34
- attr_reader :asset
62
+ attr_reader :asset, :blob
35
63
 
36
64
  # Provides the route helpers depending on whether the URL is generated to
37
65
  # the local host or an external CDN (remote).
@@ -80,24 +108,199 @@ module Decidim
80
108
  }.compact
81
109
  end
82
110
 
83
- # Converts the variation URLs last part to the correct file extension in
84
- # case the variation has a different format than the original image.
111
+ # Most of the times the current host should be set through the controller
112
+ # already when the logic below is unnecessary. This logic is needed e.g.
113
+ # for serializers where the request context is not available.
114
+ #
115
+ # @param record The record for which to check the organization
116
+ # @param opts Options for building the URL
117
+ # @return [void]
118
+ def ensure_current_host(record, **opts)
119
+ return if asset_url_available?
120
+
121
+ options = remote? ? remote_storage_options : routes.default_url_options
122
+ options = options.merge(opts)
123
+
124
+ if opts[:host].blank? && record.present?
125
+ organization = organization_for(record)
126
+ options[:host] = organization.host if organization
127
+ end
128
+
129
+ uri =
130
+ if options[:protocol] == "https" || options[:scheme] == "https"
131
+ URI::HTTPS.build(options)
132
+ else
133
+ URI::HTTP.build(options)
134
+ end
135
+
136
+ ActiveStorage::Current.host = uri.to_s
137
+ end
138
+
139
+ # Determines the organization for the passed record.
85
140
  #
86
- # @return [String] The converted representation URL
141
+ # @param record The record for which to fetch the organization
142
+ # @return [Decidim::Organization, nil] The organization for the record or
143
+ # `nil` if the organization cannot be determined
144
+ def organization_for(record)
145
+ if record.is_a?(Decidim::Organization)
146
+ record
147
+ elsif record.respond_to?(:organization)
148
+ record.organization
149
+ end
150
+ end
151
+
152
+ # Returns the URL for the given blob object.
153
+ #
154
+ # @param blob The blob object
155
+ # @param options Options for building the URL
156
+ # @return [String, nil] The URL to the blob object or `nil` if the blob is
157
+ # not defined.
158
+ def blob_url(**options)
159
+ return unless blob
160
+
161
+ if options[:only_path] || remote? || !asset_url_available?
162
+ routes.rails_blob_url(blob, **default_options.merge(options))
163
+ else
164
+ blob.url(**options)
165
+ end
166
+ end
167
+
168
+ # Returns a representation URL for the asset either directly through the
169
+ # storage service or through the Rails representation URL in case the
170
+ # path URL is requested or if the asset variant has not been processed yet
171
+ # and is not therefore yet stored at the storage service.
172
+ #
173
+ # @return [String] The representation URL for the image variant
87
174
  def representation_url(**options)
175
+ return rails_representation_url(**options) if options[:only_path] || remote?
176
+
177
+ representation_url = variant_url(**options)
178
+ return representation_url if representation_url.present?
179
+
180
+ # In case the representation has not been processed yet, it may not have
181
+ # a representation URL yet and it therefore needs to be served through
182
+ # the local representation URL for the first time (or until it has been
183
+ # processed).
184
+ if options[:host]
185
+ rails_representation_url(**options)
186
+ else
187
+ representation_url(**options.merge(only_path: true))
188
+ end
189
+ end
190
+
191
+ # Returns the local Rails representation URL meaning that the asset will
192
+ # be served through the service itself. This may be necessary if the asset
193
+ # variant (e.g. a thumbnail) has not been processed yet because the
194
+ # variant representation has not been requested before.
195
+ #
196
+ # Due to performance reasons it is advised to avoid requesting the assets
197
+ # through the Rails representation URLs when possible because that causes
198
+ # a lot of requests to the Rails backend and slowness to the service under
199
+ # heavy loads.
200
+ #
201
+ # Converts the variation URLs last part to the correct file extension in
202
+ # case the variation has a different format than the original image. The
203
+ # conversion needs to be only done for the Rails representation URLs
204
+ # because once the image is stored at the storage service, it already has
205
+ # the correct file extension.
206
+ #
207
+ # @param options The options for building the URL
208
+ # @return [String, nil] The converted representation URL or `nil` if the
209
+ # asset is not defined.
210
+ def rails_representation_url(**options)
211
+ return unless asset
212
+
88
213
  representation_url = routes.rails_representation_url(asset, **default_options.merge(options))
214
+
89
215
  variation = asset.try(:variation)
90
216
  return representation_url unless variation
91
217
 
92
218
  format = variation.try(:format)
93
219
  return representation_url unless format
220
+ return unless blob
94
221
 
95
- original_ext = File.extname(asset.blob.filename.to_s)
222
+ original_ext = File.extname(blob.filename.to_s)
96
223
  return representation_url if original_ext == ".#{format}"
97
224
 
98
- basename = File.basename(asset.blob.filename.to_s, original_ext)
225
+ basename = File.basename(blob.filename.to_s, original_ext)
99
226
  representation_url.sub(/#{basename}\.#{original_ext.tr(".", "")}$/, "#{basename}.#{format}")
100
227
  end
228
+
229
+ # Fetches the image variant's URL at the storage service if the variant
230
+ # has already been processed and is stored at the storage service. If the
231
+ # variant has not been processed yet, returns `nil` in which case the
232
+ # variant has to be served through the service's own representation URL
233
+ # causing it to be processed and stored at the storage service.
234
+ #
235
+ # @param options The options for building the URL
236
+ # @return [String, nil] The variant URL at the storage service or `nil` if
237
+ # the variant has not been processed yet and does not yet exist at the
238
+ # storage service or `nil` when the asset is not defined
239
+ def variant_url(**options)
240
+ return unless asset
241
+ return unless asset_url_available?
242
+ return unless asset_exist?
243
+
244
+ case asset
245
+ when ActiveStorage::VariantWithRecord
246
+ # This is used when `ActiveStorage.track_variants` is enabled through
247
+ # `config.active_storage.track_variants`. In case the variant has not
248
+ # been processed yet, the `#url` method would return nil.
249
+ #
250
+ # Note that if the `asset.processed?` returns `true`, the variant
251
+ # record has been created in the database but it does not mean that
252
+ # it has been uploaded to the storage service yet. Likely a bug in
253
+ # ActiveStorage but to be sure that the asset is uploaded to the
254
+ # storage service, we also check that.
255
+ asset.url(**options) if asset.processed?
256
+ else # ActiveStorage::Variant
257
+ # Check whether the variant exists at the storage service before
258
+ # returning its URL. Otherwise the URL would be returned even when the
259
+ # variant is not yet processed causing 404 errors for the images on
260
+ # the page.
261
+ #
262
+ # Note that the `ActiveStorage::Variant#url` method only accepts
263
+ # certain keyword arguments where as the other objects allow any
264
+ # keyword arguments.
265
+ possible_kwargs = asset.method(:url).parameters.select { |p| p[0] == :key }.map { |p| p[1] }
266
+ asset.url(**options.slice(*possible_kwargs))
267
+ end
268
+ end
269
+
270
+ # Determines if the asset exists at the storage service.
271
+ #
272
+ # @return [Boolean] A boolean answering the question "does this asset
273
+ # exist at the storage service?".
274
+ def asset_exist?
275
+ return false if asset.key.blank?
276
+
277
+ blob.service.exist?(asset.key)
278
+ end
279
+
280
+ # Determines if the current host is required to build the asset URL.
281
+ #
282
+ # @return [Boolean] A boolean indicating if the current host is required
283
+ # to build the asset URL.
284
+ def current_host_required?
285
+ return false unless blob
286
+ return false unless defined?(ActiveStorage::Service::DiskService)
287
+
288
+ blob.service.is_a?(ActiveStorage::Service::DiskService)
289
+ end
290
+
291
+ # Determines if the asset URL can be generated.
292
+ #
293
+ # @return [Boolean] A boolean indicating if the asset URL can be
294
+ # generated.
295
+ def asset_url_available?
296
+ # If the service is an external service, the URL can be generated
297
+ # regardless of the current host being set.
298
+ return true unless current_host_required?
299
+
300
+ # For the disk service, the URL can be only generated if the current
301
+ # host has been set.
302
+ ActiveStorage::Current.host.present?
303
+ end
101
304
  end
102
305
  end
103
306
  end
@@ -237,6 +237,14 @@ module Decidim
237
237
  app.config.action_mailer.deliver_later_queue_name = :mailers
238
238
  end
239
239
 
240
+ initializer "decidim_core.signed_global_id", after: "global_id" do |app|
241
+ next if app.config.global_id.fetch(:expires_in, nil).present?
242
+
243
+ config.after_initialize do
244
+ SignedGlobalID.expires_in = nil
245
+ end
246
+ end
247
+
240
248
  initializer "decidim_core.middleware" do |app|
241
249
  if app.config.public_file_server.enabled
242
250
  headers = app.config.public_file_server.headers || {}
@@ -10,7 +10,7 @@ shared_examples_for "attachable interface" do
10
10
 
11
11
  it "includes the attachment urls" do
12
12
  attachment_urls = response["attachments"].map { |attachment| attachment["url"] }
13
- expect(attachment_urls).to include(*attachments.map(&:url))
13
+ expect(attachment_urls).to include_blob_urls(*attachments.map(&:file).map(&:blob))
14
14
  end
15
15
  end
16
16
  end
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- shared_examples "follows" do
3
+ # When using these shared examples, make sure there are no prior requests within
4
+ # the same group of examples where this is included. Otherwise you may end up
5
+ # in race conditions that cause these to fail as explained at:
6
+ # https://github.com/decidim/decidim/pull/6161
7
+ shared_examples "followable content for users" do
4
8
  before do
9
+ switch_to_host(organization.host)
5
10
  login_as user, scope: :user
6
11
  end
7
12
 
@@ -34,9 +39,9 @@ shared_examples "follows" do
34
39
  end
35
40
  end
36
41
 
37
- shared_examples "follows with a component" do
42
+ shared_examples "followable content for users with a component" do
38
43
  include_context "with a component"
39
- include_examples "follows"
44
+ include_examples "followable content for users"
40
45
 
41
46
  context "when the user is following the followable's participatory space" do
42
47
  before do
@@ -1,22 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  shared_examples "a paginated resource" do
4
- let(:collection_size) { 30 }
4
+ let(:collection_size) { 50 }
5
5
 
6
6
  before do
7
7
  visit_component
8
8
  end
9
9
 
10
- it "lists 10 resources per page by default" do
11
- expect(page).to have_css(resource_selector, count: 10)
12
- expect(page).to have_css("[data-pages] [data-page]", count: 3)
10
+ it "lists 25 resources per page by default" do
11
+ expect(page).to have_css(resource_selector, count: 25)
12
+ expect(page).to have_css("[data-pages] [data-page]", count: 2)
13
13
  end
14
14
 
15
15
  it "results per page can be changed from the selector" do
16
16
  expect(page).to have_css("[data-pagination]")
17
17
 
18
18
  within "[data-pagination]" do
19
- page.find("summary", text: "10").click
19
+ page.find("summary", text: "25").click
20
20
  click_link "50"
21
21
  end
22
22
 
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.28.2"
7
+ "0.28.3"
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+
5
+ module Decidim
6
+ class SevenZipWrapper
7
+ class << self
8
+ def compress_and_encrypt(filename:, password:, input_directory:)
9
+ run("cd #{escape(input_directory)} && 7z a -tzip -p#{escape(password)} -mem=AES256 #{escape(filename)} .")
10
+ end
11
+
12
+ def extract_and_decrypt(filename:, password:, output_directory:)
13
+ run("7z x -tzip #{escape(filename)} -o#{escape(output_directory)} -p#{escape(password)}")
14
+ end
15
+
16
+ private
17
+
18
+ def run(command)
19
+ success = system(command)
20
+
21
+ raise "Command failed: #{command}" unless success
22
+ end
23
+
24
+ def escape(string)
25
+ Shellwords.escape(string)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,7 +2,107 @@
2
2
 
3
3
  namespace :decidim do
4
4
  namespace :upgrade do
5
- desc "Remove orphan categorizations"
5
+ namespace :clean do
6
+ desc "Removes all the invalid records from search, notifications, follows and action_logs"
7
+ task invalid_records: [
8
+ :"decidim:upgrade:clean:searchable_resources",
9
+ :"decidim:upgrade:clean:notifications",
10
+ :"decidim:upgrade:clean:follows",
11
+ :"decidim:upgrade:clean:action_logs"
12
+ ]
13
+
14
+ desc "Removes any action logs belonging to invalid resources"
15
+ task :action_logs, [] => :environment do
16
+ puts "=== Deleting Action logs\n"
17
+ invalid = 0
18
+ Decidim::ActionLog.find_each do |log|
19
+ log.participatory_space if log.participatory_space_type.present?
20
+ log.resource if log.resource_type.present?
21
+
22
+ if log.resource_type == "Decidim::Component" && log.resource.blank?
23
+ log.delete
24
+ invalid += 1
25
+ end
26
+
27
+ next if log.decidim_component_id.blank?
28
+ next if log.component.present?
29
+
30
+ log.delete
31
+ invalid += 1
32
+ rescue NameError
33
+ log.delete
34
+ invalid += 1
35
+ end
36
+ puts "===== Deleted #{invalid} invalid action logs\n"
37
+ end
38
+
39
+ desc "Removes any follows belonging to invalid resources"
40
+ task :follows, [] => :environment do
41
+ puts "=== Deleting Follows\n"
42
+ invalid = 0
43
+ Decidim::Follow.find_each do |follow|
44
+ follow.followable
45
+
46
+ next unless follow.followable.respond_to?(:component)
47
+ next if follow.followable.component.present?
48
+
49
+ # We attempt to remove any of the follows that refer to spaces or components that disappeared
50
+ follow.destroy
51
+ invalid += 1
52
+ rescue NameError
53
+ # We use delete as we do not want to call the hooks
54
+ follow.delete
55
+ invalid += 1
56
+ end
57
+ puts "===== Deleted #{invalid} invalid follows\n"
58
+ end
59
+
60
+ desc "Removes any notifications belonging to invalid resources"
61
+ task :notifications, [] => :environment do
62
+ puts "=== Deleting Notification\n"
63
+ invalid = 0
64
+ Decidim::Notification.find_each do |notification|
65
+ # Check if the resource class still exists
66
+ notification.resource
67
+ # Check if the event class still exists
68
+ notification.event_class_instance
69
+ rescue NameError
70
+ notification.destroy
71
+ invalid += 1
72
+ end
73
+ puts "===== Deleted #{invalid} invalid notifications\n"
74
+ end
75
+
76
+ desc "Removes any resources from search index that do not exist"
77
+ task :searchable_resources, [] => :environment do
78
+ puts "=== Deleting Searchable results\n"
79
+ puts "==== Deleting invalid spaces \n"
80
+ invalid = 0
81
+ Decidim::SearchableResource.where.not(decidim_participatory_space_type: nil).find_each do |search|
82
+ search.decidim_participatory_space
83
+ rescue NameError
84
+ search.destroy!
85
+ invalid += 1
86
+ end
87
+ puts "===== Deleted #{invalid} invalid spaces\n"
88
+
89
+ puts "==== Deleting invalid resources from search index \n"
90
+ invalid = 0
91
+ Decidim::SearchableResource.find_each do |search|
92
+ next unless search.resource.respond_to?(:component)
93
+ next if search.resource.component.present?
94
+
95
+ search.destroy
96
+ invalid += 1
97
+ rescue NameError
98
+ search.destroy!
99
+ invalid += 1
100
+ end
101
+ puts "===== Deleted #{invalid} invalid resources\n"
102
+ end
103
+ end
104
+
105
+ desc "Removes orphan categorizations"
6
106
  task fix_orphan_categorizations: :environment do
7
107
  logger = Logger.new($stdout)
8
108
  logger.info("Removing orphan categorizations...")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.2
4
+ version: 0.28.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep Jaume Rey Peroy
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-07-16 00:00:00.000000000 Z
13
+ date: 2024-09-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: active_link_to
@@ -688,20 +688,6 @@ dependencies:
688
688
  - - "~>"
689
689
  - !ruby/object:Gem::Version
690
690
  version: '2.0'
691
- - !ruby/object:Gem::Dependency
692
- name: seven_zip_ruby
693
- requirement: !ruby/object:Gem::Requirement
694
- requirements:
695
- - - "~>"
696
- - !ruby/object:Gem::Version
697
- version: '1.3'
698
- type: :runtime
699
- prerelease: false
700
- version_requirements: !ruby/object:Gem::Requirement
701
- requirements:
702
- - - "~>"
703
- - !ruby/object:Gem::Version
704
- version: '1.3'
705
691
  - !ruby/object:Gem::Dependency
706
692
  name: shakapacker
707
693
  requirement: !ruby/object:Gem::Requirement
@@ -764,28 +750,28 @@ dependencies:
764
750
  requirements:
765
751
  - - '='
766
752
  - !ruby/object:Gem::Version
767
- version: 0.28.2
753
+ version: 0.28.3
768
754
  type: :development
769
755
  prerelease: false
770
756
  version_requirements: !ruby/object:Gem::Requirement
771
757
  requirements:
772
758
  - - '='
773
759
  - !ruby/object:Gem::Version
774
- version: 0.28.2
760
+ version: 0.28.3
775
761
  - !ruby/object:Gem::Dependency
776
762
  name: decidim-dev
777
763
  requirement: !ruby/object:Gem::Requirement
778
764
  requirements:
779
765
  - - '='
780
766
  - !ruby/object:Gem::Version
781
- version: 0.28.2
767
+ version: 0.28.3
782
768
  type: :development
783
769
  prerelease: false
784
770
  version_requirements: !ruby/object:Gem::Requirement
785
771
  requirements:
786
772
  - - '='
787
773
  - !ruby/object:Gem::Version
788
- version: 0.28.2
774
+ version: 0.28.3
789
775
  description: Adds core features so other engines can hook into the framework.
790
776
  email:
791
777
  - josepjaume@gmail.com
@@ -1880,7 +1866,6 @@ files:
1880
1866
  - app/services/decidim/static_map_generator.rb
1881
1867
  - app/services/decidim/tokenizer.rb
1882
1868
  - app/services/decidim/traceability.rb
1883
- - app/services/decidim/zip_stream/writer.rb
1884
1869
  - app/uploaders/decidim/application_uploader.rb
1885
1870
  - app/uploaders/decidim/attachment_uploader.rb
1886
1871
  - app/uploaders/decidim/avatar_uploader.rb
@@ -2814,6 +2799,7 @@ files:
2814
2799
  - lib/decidim/searchable.rb
2815
2800
  - lib/decidim/seeds.rb
2816
2801
  - lib/decidim/settings_manifest.rb
2802
+ - lib/decidim/seven_zip_wrapper.rb
2817
2803
  - lib/decidim/shareable_with_token.rb
2818
2804
  - lib/decidim/snippets.rb
2819
2805
  - lib/decidim/social_share_service_manifest.rb
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Decidim
4
- module ZipStream
5
- module Writer
6
- def add_user_data_to_zip_stream(out, user_data)
7
- user_data.each do |element|
8
- filename_file = element.last.filename(element.first.parameterize)
9
-
10
- out.put_next_entry(filename_file)
11
- if element.last.read.presence
12
- out.write element.last.read
13
- else
14
- out.write "No data"
15
- end
16
- end
17
- end
18
-
19
- def add_attachments_to_zip_stream(out, export_attachments)
20
- export_attachments.each do |attachment_block|
21
- next if attachment_block.last.nil?
22
-
23
- folder_name = attachment_block.first.parameterize
24
- attachment_block.last.each do |attachment|
25
- next unless attachment.attached?
26
-
27
- blobs = attachment.is_a?(ActiveStorage::Attached::One) ? [attachment.blob] : attachment.blobs
28
- blobs.each do |blob|
29
- out.put_next_entry("#{folder_name}/#{blob.filename}")
30
- blob.open do |f|
31
- out << f.read
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end