decidim-assemblies 0.19.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/decidim/assemblies/assembly.svg +1 -3
  3. data/app/assets/javascripts/decidim/assemblies/orgchart.js.es6 +698 -0
  4. data/app/cells/decidim/assemblies/assembly_m/footer.erb +2 -2
  5. data/app/cells/decidim/assemblies/assembly_m_cell.rb +5 -5
  6. data/app/cells/decidim/assemblies/assembly_member/show.erb +4 -4
  7. data/app/cells/decidim/assemblies/content_blocks/highlighted_assemblies/show.erb +10 -11
  8. data/app/cells/decidim/assemblies/content_blocks/highlighted_assemblies_cell.rb +1 -0
  9. data/app/commands/decidim/assemblies/admin/create_assemblies_type.rb +45 -0
  10. data/app/commands/decidim/assemblies/admin/create_assembly.rb +1 -2
  11. data/app/commands/decidim/assemblies/admin/create_assembly_admin.rb +2 -1
  12. data/app/commands/decidim/assemblies/admin/create_assembly_member.rb +12 -3
  13. data/app/commands/decidim/assemblies/admin/destroy_assemblies_type.rb +45 -0
  14. data/app/commands/decidim/assemblies/admin/import_assembly.rb +72 -0
  15. data/app/commands/decidim/assemblies/admin/notify_role_assigned_to_assembly.rb +22 -0
  16. data/app/commands/decidim/assemblies/admin/update_assemblies_setting.rb +46 -0
  17. data/app/commands/decidim/assemblies/admin/update_assemblies_type.rb +46 -0
  18. data/app/commands/decidim/assemblies/admin/update_assembly.rb +11 -7
  19. data/app/commands/decidim/assemblies/admin/update_assembly_admin.rb +2 -1
  20. data/app/controllers/concerns/decidim/assemblies/admin/filterable.rb +30 -0
  21. data/app/controllers/decidim/assemblies/admin/assemblies_controller.rb +8 -29
  22. data/app/controllers/decidim/assemblies/admin/assemblies_settings_controller.rb +49 -0
  23. data/app/controllers/decidim/assemblies/admin/assemblies_types_controller.rb +107 -0
  24. data/app/controllers/decidim/assemblies/admin/assembly_exports_controller.rb +24 -0
  25. data/app/controllers/decidim/assemblies/admin/assembly_imports_controller.rb +31 -0
  26. data/app/controllers/decidim/assemblies/admin/assembly_user_roles_controller.rb +2 -1
  27. data/app/controllers/decidim/assemblies/assemblies_controller.rb +6 -2
  28. data/app/controllers/decidim/assemblies/{assembly_widgets_controller.rb → widgets_controller.rb} +2 -2
  29. data/app/events/decidim/assemblies/create_assembly_member_event.rb +17 -0
  30. data/app/events/decidim/role_assigned_to_assembly_event.rb +28 -0
  31. data/app/forms/decidim/assemblies/admin/assemblies_setting_form.rb +14 -0
  32. data/app/forms/decidim/assemblies/admin/assemblies_type_form.rb +17 -0
  33. data/app/forms/decidim/assemblies/admin/assembly_form.rb +37 -19
  34. data/app/forms/decidim/assemblies/admin/assembly_import_form.rb +83 -0
  35. data/app/forms/decidim/assemblies/admin/assembly_user_role_form.rb +8 -2
  36. data/app/helpers/decidim/assemblies/admin/assemblies_helper.rb +6 -0
  37. data/app/helpers/decidim/assemblies/assemblies_helper.rb +6 -3
  38. data/app/helpers/decidim/assemblies/filter_assemblies_helper.rb +10 -7
  39. data/app/models/decidim/assemblies_setting.rb +17 -0
  40. data/app/models/decidim/assemblies_type.rb +27 -0
  41. data/app/models/decidim/assembly.rb +39 -3
  42. data/app/models/decidim/assembly_user_role.rb +1 -1
  43. data/app/permissions/decidim/assemblies/permissions.rb +60 -2
  44. data/app/presenters/decidim/assemblies/admin_log/assemblies_setting_presenter.rb +27 -0
  45. data/app/presenters/decidim/assemblies/admin_log/assemblies_type_presenter.rb +43 -0
  46. data/app/presenters/decidim/assemblies/admin_log/assembly_presenter.rb +1 -2
  47. data/app/presenters/decidim/assemblies/assembly_presenter.rb +29 -0
  48. data/app/presenters/decidim/assemblies/assembly_stats_presenter.rb +1 -1
  49. data/app/presenters/decidim/log/value_types/assembly_type_presenter.rb +29 -0
  50. data/app/queries/decidim/assemblies/filtered_assemblies.rb +2 -2
  51. data/app/queries/decidim/assemblies/parent_assemblies_for_select.rb +42 -0
  52. data/app/serializers/decidim/assemblies/assembly_importer.rb +172 -0
  53. data/app/serializers/decidim/assemblies/assembly_serializer.rb +147 -0
  54. data/app/services/decidim/assemblies/assembly_search.rb +3 -3
  55. data/app/types/decidim/assemblies/assemblies_type_type.rb +17 -0
  56. data/app/types/decidim/assemblies/assembly_member_type.rb +29 -0
  57. data/app/types/decidim/assemblies/assembly_type.rb +67 -0
  58. data/app/views/decidim/assemblies/_filter_by_type.html.erb +11 -7
  59. data/app/views/decidim/assemblies/admin/assemblies/_form.html.erb +2 -6
  60. data/app/views/decidim/assemblies/admin/assemblies/index.html.erb +18 -4
  61. data/app/views/decidim/assemblies/admin/assemblies_settings/_form.html.erb +10 -0
  62. data/app/views/decidim/assemblies/admin/assemblies_settings/edit.html.erb +6 -0
  63. data/app/views/decidim/assemblies/admin/assemblies_types/_form.html.erb +11 -0
  64. data/app/views/decidim/assemblies/admin/assemblies_types/edit.html.erb +6 -0
  65. data/app/views/decidim/assemblies/admin/assemblies_types/index.html.erb +43 -0
  66. data/app/views/decidim/assemblies/admin/assemblies_types/new.html.erb +7 -0
  67. data/app/views/decidim/assemblies/admin/assembly_imports/_form.html.erb +46 -0
  68. data/app/views/decidim/assemblies/admin/assembly_imports/new.html.erb +7 -0
  69. data/app/views/decidim/assemblies/admin/assembly_members/index.html.erb +30 -30
  70. data/app/views/decidim/assemblies/assemblies/_parent_assemblies.html.erb +2 -2
  71. data/app/views/decidim/assemblies/assemblies/_promoted_assembly.html.erb +3 -3
  72. data/app/views/decidim/assemblies/assemblies/index.html.erb +11 -8
  73. data/app/views/decidim/assemblies/assemblies/show.html.erb +11 -14
  74. data/app/views/decidim/assemblies/assembly_members/index.html.erb +1 -1
  75. data/app/views/layouts/decidim/admin/assemblies.html.erb +22 -0
  76. data/app/views/layouts/decidim/admin/assembly.html.erb +2 -2
  77. data/app/views/layouts/decidim/assembly.html.erb +1 -0
  78. data/config/locales/am-ET.yml +1 -0
  79. data/config/locales/ar.yml +60 -27
  80. data/config/locales/bg-BG.yml +7 -0
  81. data/config/locales/bg.yml +7 -0
  82. data/config/locales/ca.yml +101 -1
  83. data/config/locales/cs.yml +152 -52
  84. data/config/locales/da-DK.yml +1 -0
  85. data/config/locales/da.yml +1 -0
  86. data/config/locales/de.yml +99 -0
  87. data/config/locales/el-GR.yml +1 -0
  88. data/config/locales/el.yml +475 -0
  89. data/config/locales/en.yml +100 -0
  90. data/config/locales/eo.yml +1 -0
  91. data/config/locales/es-MX.yml +100 -0
  92. data/config/locales/es-PY.yml +100 -0
  93. data/config/locales/es.yml +100 -0
  94. data/config/locales/et-EE.yml +1 -0
  95. data/config/locales/et.yml +1 -0
  96. data/config/locales/eu.yml +11 -0
  97. data/config/locales/fi-plain.yml +97 -0
  98. data/config/locales/fi.yml +103 -6
  99. data/config/locales/fr-CA.yml +478 -0
  100. data/config/locales/fr.yml +100 -0
  101. data/config/locales/ga-IE.yml +1 -0
  102. data/config/locales/gl.yml +11 -0
  103. data/config/locales/hr-HR.yml +1 -0
  104. data/config/locales/hr.yml +1 -0
  105. data/config/locales/hu.yml +85 -2
  106. data/config/locales/id-ID.yml +11 -0
  107. data/config/locales/is-IS.yml +263 -0
  108. data/config/locales/is.yml +263 -0
  109. data/config/locales/it.yml +171 -74
  110. data/config/locales/ja-JP.yml +471 -0
  111. data/config/locales/ja.yml +471 -0
  112. data/config/locales/ko-KR.yml +1 -0
  113. data/config/locales/ko.yml +1 -0
  114. data/config/locales/lt-LT.yml +1 -0
  115. data/config/locales/lt.yml +1 -0
  116. data/config/locales/lv.yml +454 -0
  117. data/config/locales/mt-MT.yml +1 -0
  118. data/config/locales/mt.yml +1 -0
  119. data/config/locales/nl.yml +103 -6
  120. data/config/locales/no.yml +349 -7
  121. data/config/locales/om-ET.yml +1 -0
  122. data/config/locales/pl.yml +250 -151
  123. data/config/locales/pt-BR.yml +12 -1
  124. data/config/locales/pt.yml +217 -118
  125. data/config/locales/ro-RO.yml +441 -0
  126. data/config/locales/ru.yml +11 -0
  127. data/config/locales/sk-SK.yml +168 -0
  128. data/config/locales/sk.yml +172 -0
  129. data/config/locales/sl.yml +283 -0
  130. data/config/locales/so-SO.yml +1 -0
  131. data/config/locales/sr-CS.yml +73 -0
  132. data/config/locales/sv.yml +188 -88
  133. data/config/locales/ti-ER.yml +1 -0
  134. data/config/locales/tr-TR.yml +30 -0
  135. data/config/locales/uk.yml +11 -0
  136. data/config/locales/vi-VN.yml +1 -0
  137. data/config/locales/vi.yml +1 -0
  138. data/config/locales/zh-CN.yml +471 -0
  139. data/config/locales/zh-TW.yml +1 -0
  140. data/db/migrate/20200108113855_create_decidim_assembly_types.rb +19 -0
  141. data/db/migrate/20200108123050_migrate_decidim_assembly_types.rb +83 -0
  142. data/db/migrate/20200320105906_index_foreign_keys_in_decidim_assemblies.rb +7 -0
  143. data/db/migrate/20200320105907_index_foreign_keys_in_decidim_assembly_user_roles.rb +7 -0
  144. data/db/migrate/20200416132109_remove_legacy_decidim_assembly_type.rb +8 -0
  145. data/db/migrate/20200430202456_create_decidim_assemblies_settings.rb +10 -0
  146. data/db/seeds/city.jpeg +0 -0
  147. data/db/seeds/city2.jpeg +0 -0
  148. data/lib/decidim/assemblies/admin_engine.rb +10 -0
  149. data/lib/decidim/assemblies/engine.rb +8 -1
  150. data/lib/decidim/assemblies/participatory_space.rb +31 -15
  151. data/lib/decidim/assemblies/query_extensions.rb +40 -0
  152. data/lib/decidim/assemblies/test/factories.rb +32 -5
  153. data/lib/decidim/assemblies/version.rb +1 -1
  154. metadata +91 -11
  155. data/app/views/decidim/assemblies/assembly_widgets/show.html.erb +0 -11
@@ -11,7 +11,7 @@ module Decidim
11
11
  belongs_to :assembly, foreign_key: "decidim_assembly_id", class_name: "Decidim::Assembly", optional: true
12
12
  alias participatory_space assembly
13
13
 
14
- ROLES = %w(admin collaborator moderator).freeze
14
+ ROLES = %w(admin collaborator moderator valuator).freeze
15
15
  validates :role, inclusion: { in: ROLES }, uniqueness: { scope: [:user, :assembly] }
16
16
  validate :user_and_assembly_same_organization
17
17
 
@@ -30,16 +30,20 @@ module Decidim
30
30
  return permission_action unless permission_action.scope == :admin
31
31
 
32
32
  user_can_read_assembly_list?
33
+ user_can_list_assembly_list?
33
34
  user_can_read_current_assembly?
34
35
  user_can_create_assembly?
36
+ user_can_read_assemblies_setting?
35
37
 
36
38
  # org admins and space admins can do everything in the admin section
37
39
  org_admin_action?
40
+ assemblies_type_action?
38
41
 
39
42
  return permission_action unless assembly
40
43
 
41
44
  moderator_action?
42
45
  collaborator_action?
46
+ valuator_action?
43
47
  assembly_admin_action?
44
48
 
45
49
  permission_action
@@ -47,6 +51,21 @@ module Decidim
47
51
 
48
52
  private
49
53
 
54
+ def assemblies_type_action?
55
+ return unless [:assembly_type, :assemblies_type].include? permission_action.subject
56
+ return disallow! unless user.admin?
57
+
58
+ assembly_type = context.fetch(:assembly_type, nil)
59
+ case permission_action.action
60
+ when :destroy
61
+ assemblies_is_empty = assembly_type && assembly_type.assemblies.empty?
62
+
63
+ toggle_allow(assemblies_is_empty)
64
+ else
65
+ allow!
66
+ end
67
+ end
68
+
50
69
  # It's an admin user if it's an organization admin or is a space admin
51
70
  # for the current `assembly`.
52
71
  def admin_user?
@@ -148,6 +167,13 @@ module Decidim
148
167
  toggle_allow(user.admin?)
149
168
  end
150
169
 
170
+ def user_can_read_assemblies_setting?
171
+ return unless permission_action.action == :read &&
172
+ permission_action.subject == :assemblies_setting
173
+
174
+ toggle_allow(user.admin?)
175
+ end
176
+
151
177
  # Everyone can read the assembly list
152
178
  def user_can_read_assembly_list?
153
179
  return unless read_assembly_list_permission_action?
@@ -155,6 +181,25 @@ module Decidim
155
181
  toggle_allow(user.admin? || has_manageable_assemblies?)
156
182
  end
157
183
 
184
+ # Checks whether the user can list the current given assembly or not.
185
+ #
186
+ # In case of user being admin of child assembly even parent assembly
187
+ # should be listed to be able to navigate to child assembly
188
+ def user_can_list_assembly_list?
189
+ return unless permission_action.action == :list &&
190
+ permission_action.subject == :assembly
191
+
192
+ toggle_allow(user.admin? || allowed_list_of_assemblies?)
193
+ end
194
+
195
+ def allowed_list_of_assemblies?
196
+ assemblies = AssembliesWithUserRole.for(user)
197
+ parent_assemblies = assemblies.flat_map { |assembly| [assembly.id] + assembly.ancestors.pluck(:id) }
198
+
199
+ allowed_list_of_assemblies = Decidim::Assembly.where(id: assemblies + parent_assemblies)
200
+ allowed_list_of_assemblies.uniq.member?(assembly)
201
+ end
202
+
158
203
  def user_can_read_current_assembly?
159
204
  return unless read_assembly_list_permission_action?
160
205
  return if permission_action.subject == :assembly_list
@@ -177,6 +222,14 @@ module Decidim
177
222
  allow! if permission_action.action == :read || permission_action.action == :preview
178
223
  end
179
224
 
225
+ # Valuators can only read the assembly components
226
+ def valuator_action?
227
+ return unless can_manage_assembly?(role: :valuator)
228
+
229
+ allow! if permission_action.action == :read && permission_action.subject == :component
230
+ allow! if permission_action.action == :export && permission_action.subject == :component_data
231
+ end
232
+
180
233
  # Process admins can perform everything *inside* that assembly. They cannot
181
234
  # create a assembly or perform actions on assembly groups or other
182
235
  # assemblies.
@@ -196,7 +249,9 @@ module Decidim
196
249
  :assembly,
197
250
  :assembly_user_role,
198
251
  :assembly_member,
199
- :space_private_user
252
+ :space_private_user,
253
+ :export_space,
254
+ :import
200
255
  ].include?(permission_action.subject)
201
256
  allow! if is_allowed
202
257
  end
@@ -214,7 +269,10 @@ module Decidim
214
269
  :assembly,
215
270
  :assembly_user_role,
216
271
  :assembly_member,
217
- :space_private_user
272
+ :space_private_user,
273
+ :export_space,
274
+ :import,
275
+ :assemblies_setting
218
276
  ].include?(permission_action.subject)
219
277
  allow! if is_allowed
220
278
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Assemblies
5
+ module AdminLog
6
+ # This class holds the logic to present a `Decidim::AssembliesSetting`
7
+ # for the `AdminLog` log.
8
+ #
9
+ # Usage should be automatic and you shouldn't need to call this class
10
+ # directly, but here's an example:
11
+ #
12
+ # action_log = Decidim::ActionLog.last
13
+ # view_helpers # => this comes from the views
14
+ # AssembliesSettingPresenter.new(action_log, view_helpers).present
15
+ class AssembliesSettingPresenter < Decidim::Log::BasePresenter
16
+ private
17
+
18
+ def action_string
19
+ case action
20
+ when "update"
21
+ "decidim.admin_log.assembly_setting.#{action}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Assemblies
5
+ module AdminLog
6
+ # This class holds the logic to present a `Decidim::AssembliesType`
7
+ # for the `AdminLog` log.
8
+ #
9
+ # Usage should be automatic and you shouldn't need to call this class
10
+ # directly, but here's an example:
11
+ #
12
+ # action_log = Decidim::ActionLog.last
13
+ # view_helpers # => this comes from the views
14
+ # AssembliesTypePresenter.new(action_log, view_helpers).present
15
+ class AssembliesTypePresenter < Decidim::Log::BasePresenter
16
+ private
17
+
18
+ def diff_fields_mapping
19
+ {
20
+ title: :i18n
21
+ }
22
+ end
23
+
24
+ def i18n_labels_scope
25
+ "activemodel.attributes.assemblies_type"
26
+ end
27
+
28
+ def action_string
29
+ case action
30
+ when "create", "delete", "update"
31
+ "decidim.admin_log.assembly_type.#{action}"
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def has_diff?
38
+ action == "delete" || super
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -37,8 +37,7 @@ module Decidim
37
37
  target: :i18n,
38
38
  title: :i18n,
39
39
  purpose_of_action: :i18n,
40
- assembly_type: :string,
41
- assembly_type_other: :i8n,
40
+ decidim_assemblies_type_id: :assembly_type,
42
41
  creation_date: :date,
43
42
  created_by: :string,
44
43
  created_by_other: :i18n,
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Assemblies
5
+ class AssemblyPresenter < SimpleDelegator
6
+ include Rails.application.routes.mounted_helpers
7
+ include ActionView::Helpers::UrlHelper
8
+
9
+ delegate :url, to: :hero_image, prefix: true
10
+ delegate :url, to: :banner_image, prefix: true
11
+
12
+ def hero_image_url
13
+ return if assembly.hero_image.blank?
14
+
15
+ URI.join(decidim.root_url(host: assembly.organization.host), assembly.hero_image_url).to_s
16
+ end
17
+
18
+ def banner_image_url
19
+ return if assembly.banner_image.blank?
20
+
21
+ URI.join(decidim.root_url(host: assembly.organization.host), assembly.banner_image_url).to_s
22
+ end
23
+
24
+ def assembly
25
+ __getobj__
26
+ end
27
+ end
28
+ end
29
+ end
@@ -38,7 +38,7 @@ module Decidim
38
38
 
39
39
  def render_stats_data(component_manifest, name, data, index)
40
40
  safe_join([
41
- index.zero? ? manifest_icon(component_manifest) : " /&nbsp".html_safe,
41
+ index.zero? ? manifest_icon(component_manifest, role: "img", "aria-hidden": true) : " /&nbsp".html_safe,
42
42
  content_tag(:span, "#{number_with_delimiter(data)} " + I18n.t(name, scope: "decidim.assemblies.statistics"),
43
43
  class: "#{name} process_stats-text")
44
44
  ])
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Log
5
+ module ValueTypes
6
+ # This class presents the given value as a Decidim::AssembliesType. Check
7
+ # the `DefaultPresenter` for more info on how value
8
+ # presenters work.
9
+ class AssemblyTypePresenter < DefaultPresenter
10
+ # Public: Presents the value as a Decidim::AssembliesType. If the type can
11
+ # be found, it shows its title. Otherwise it shows its ID.
12
+ #
13
+ # Returns an HTML-safe String.
14
+ def present
15
+ return unless value
16
+ return h.translated_attribute(type.title) if type
17
+
18
+ I18n.t("not_found", id: value, scope: "decidim.log.value_types.assembly_type_presenter")
19
+ end
20
+
21
+ private
22
+
23
+ def type
24
+ @type ||= Decidim::AssembliesType.find_by(id: value)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -13,9 +13,9 @@ module Decidim
13
13
  end
14
14
 
15
15
  def query
16
- return assemblies.all if @filter == "all"
16
+ return assemblies.all if @filter.blank?
17
17
 
18
- assemblies.where(assembly_type: @filter)
18
+ assemblies.where(decidim_assemblies_type_id: @filter)
19
19
  end
20
20
  end
21
21
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Assemblies
5
+ # This query filters assemblies that can be assigned as parents for an assembly.
6
+ class ParentAssembliesForSelect < Rectify::Query
7
+ # Syntactic sugar to initialize the class and return the queried objects.
8
+ def self.for(organization, assembly)
9
+ new(organization, assembly).query
10
+ end
11
+
12
+ # Initializes the class.
13
+ def initialize(organization, assembly)
14
+ @organization = organization
15
+ @assembly = assembly
16
+ end
17
+
18
+ # Finds the available assemblies
19
+ #
20
+ # Returns an ActiveRecord::Relation.
21
+ def query
22
+ available_assemblies = Assembly.where(organization: @organization).where.not(id: @assembly)
23
+
24
+ return available_assemblies if @assembly.blank?
25
+
26
+ available_assemblies.where.not(id: descendant_ids)
27
+ end
28
+
29
+ private
30
+
31
+ def descendant_ids
32
+ recursive_children(@assembly).flatten
33
+ end
34
+
35
+ def recursive_children(model)
36
+ model.children.map do |child|
37
+ [recursive_children(child), child.id]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Assemblies
5
+ # A factory class to ensure we always create Assemblies the same way since it involves some logic.
6
+ class AssemblyImporter < Decidim::Importers::Importer
7
+ def initialize(organization, user)
8
+ @organization = organization
9
+ @user = user
10
+ end
11
+
12
+ # Public: Creates a new Assembly.
13
+ #
14
+ # attributes - The Hash of attributes to create the Assembly with.
15
+ # user - The user that performs the action.
16
+ # opts - The options MUST contain:
17
+ # - title: The +title+ for the new Assembly
18
+ # - slug: The +slug+ for the new Assembly
19
+ #
20
+ # Returns a Assembly.
21
+ def import(attributes, _user, opts)
22
+ title = opts[:title]
23
+ slug = opts[:slug]
24
+ Decidim.traceability.perform_action!(:create, Assembly, @user, visibility: "all") do
25
+ @imported_assembly = Assembly.new(
26
+ organization: @organization,
27
+ title: title,
28
+ slug: slug,
29
+ hashtag: attributes["hashtag"],
30
+ subtitle: attributes["subtitle"],
31
+ short_description: attributes["short_description"],
32
+ description: attributes["description"],
33
+ promoted: attributes["promoted"],
34
+ developer_group: attributes["developer_group"],
35
+ local_area: attributes["local_area"],
36
+ target: attributes["target"],
37
+ participatory_scope: attributes["participatory_scope"],
38
+ participatory_structure: attributes["participatory_structure"],
39
+ show_statistics: attributes["show_statistics"],
40
+ scopes_enabled: attributes["scopes_enabled"],
41
+ private_space: attributes["private_space"],
42
+ reference: attributes["reference"],
43
+ purpose_of_action: attributes["purpose_of_action"],
44
+ composition: attributes["composition"],
45
+ duration: attributes["duration"],
46
+ creation_date: attributes["creation_date"],
47
+ decidim_scope_id: attributes["decidim_scope_id"],
48
+ closing_date_reason: attributes["closing_date_reason"],
49
+ included_at: attributes["included_at"],
50
+ closing_date: attributes["closing_date"],
51
+ created_by_other: attributes["created_by_other"],
52
+ internal_organisation: attributes["internal_organisation"],
53
+ is_transparent: attributes["is_transparent"],
54
+ special_features: attributes["special_features"],
55
+ twitter_handler: attributes["twitter_handler"],
56
+ instagram_handler: attributes["instagram_handler"],
57
+ facebook_handler: attributes["facebook_handler"],
58
+ youtube_handler: attributes["youtube_handler"],
59
+ github_handler: attributes["github_handler"],
60
+ created_by: attributes["created_by"],
61
+ meta_scope: attributes["meta_scope"]
62
+ )
63
+ @imported_assembly.remote_hero_image_url = attributes["remote_hero_image_url"] if remote_file_exists?(attributes["remote_hero_image_url"])
64
+ @imported_assembly.remote_banner_image_url = attributes["remote_banner_image_url"] if remote_file_exists?(attributes["remote_banner_image_url"])
65
+ @imported_assembly.save!
66
+ @imported_assembly
67
+ end
68
+ end
69
+
70
+ def import_assemblies_type(type_id)
71
+ return if Decidim::AssembliesType.find_by(id: type_id).nil?
72
+
73
+ @imported_assembly.decidim_assemblies_type_id = type_id
74
+ end
75
+
76
+ def import_categories(categories)
77
+ return if categories.nil?
78
+
79
+ categories.map do |category_attributes|
80
+ category = Decidim.traceability.create!(
81
+ Category,
82
+ @user,
83
+ name: category_attributes["name"],
84
+ description: category_attributes["description"],
85
+ parent_id: category_attributes["parent_id"],
86
+ participatory_space: @imported_assembly
87
+ )
88
+ next if category_attributes["subcategories"].nil?
89
+
90
+ category_attributes["subcategories"].map do |subcategory_attributes|
91
+ Decidim.traceability.create!(
92
+ Category,
93
+ @user,
94
+ name: subcategory_attributes["name"],
95
+ description: subcategory_attributes["description"],
96
+ parent_id: category.id,
97
+ participatory_space: @imported_assembly
98
+ )
99
+ end
100
+ end
101
+ end
102
+
103
+ def import_folders_and_attachments(attachments)
104
+ return if attachments["files"].nil?
105
+
106
+ attachments["files"].map do |file|
107
+ next unless remote_file_exists?(file["remote_file_url"])
108
+
109
+ file_tmp = URI.open(file["remote_file_url"])
110
+
111
+ Decidim.traceability.perform_action!("create", Attachment, @user) do
112
+ attachment = Attachment.new(
113
+ title: file["title"],
114
+ description: file["description"],
115
+ content_type: file_tmp.content_type,
116
+ attached_to: @imported_assembly,
117
+ weight: file["weight"],
118
+ file: form.file, # Define attached_to before this
119
+ file_size: file_tmp.size
120
+ )
121
+ attachment.create_attachment_collection(file["attachment_collection"])
122
+ attachment.save!
123
+ attachment
124
+ end
125
+ end
126
+
127
+ attachments["attachment_collections"].map do |collection|
128
+ Decidim.traceability.perform_action!("create", AttachmentCollection, @user) do
129
+ create_attachment_collection(collection)
130
+ end
131
+ end
132
+ end
133
+
134
+ # +components+: An Array of Hashes, each corresponding with the settings of a Decidim::Component.
135
+ def import_components(components)
136
+ return if components.nil?
137
+
138
+ importer = Decidim::Importers::ParticipatorySpaceComponentsImporter.new(@imported_assembly)
139
+ importer.import(components, @user)
140
+ end
141
+
142
+ private
143
+
144
+ def create_attachment_collection(attributes)
145
+ return unless attributes.compact.any?
146
+
147
+ attachment_collection = AttachmentCollection.find_or_initialize_by(
148
+ name: attributes["name"],
149
+ weight: attributes["weight"],
150
+ description: attributes["description"],
151
+ collection_for: @imported_assembly
152
+ )
153
+ attachment_collection.save!
154
+ attachment_collection
155
+ end
156
+
157
+ def remote_file_exists?(url)
158
+ return if url.nil?
159
+
160
+ accepted = ["image", "application/pdf"]
161
+ url = URI.parse(url)
162
+ http_connection = Net::HTTP.new(url.host, url.port)
163
+ http_connection.use_ssl = true if url.scheme == "https"
164
+ http_connection.start do |http|
165
+ return http.head(url.request_uri)["Content-Type"].start_with?(*accepted)
166
+ end
167
+ rescue StandardError
168
+ nil
169
+ end
170
+ end
171
+ end
172
+ end