decidim-admin 0.23.5 → 0.24.2

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.

Potentially problematic release.


This version of decidim-admin might be problematic. Click here for more details.

Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_admin_manifest.js +1 -0
  3. data/app/assets/javascripts/decidim/admin/application.js.es6 +4 -1
  4. data/app/assets/javascripts/decidim/admin/budget_rule_toggler.component.js.es6 +23 -20
  5. data/app/assets/javascripts/decidim/admin/bundle.js +10 -17
  6. data/app/assets/javascripts/decidim/admin/bundle.js.map +1 -1
  7. data/app/assets/javascripts/decidim/admin/form.js.es6 +1 -0
  8. data/app/assets/javascripts/decidim/admin/import_guidance.js.es6 +29 -0
  9. data/app/assets/javascripts/decidim/admin/moderations.js.es6 +24 -0
  10. data/app/assets/javascripts/decidim/admin/proposal_infinite_edit.js.es6 +20 -0
  11. data/app/assets/javascripts/decidim/admin/subform_multi_toggler.component.js.es6 +2 -2
  12. data/app/assets/javascripts/decidim/admin/subform_toggler.component.js.es6 +2 -2
  13. data/app/assets/javascripts/decidim/admin/user_moderations.js +2 -0
  14. data/app/assets/stylesheets/decidim/admin/_variables.scss +9 -0
  15. data/app/assets/stylesheets/decidim/admin/components/_dropdown-menu.scss +3 -0
  16. data/app/assets/stylesheets/decidim/admin/extra/_action-icon.scss +13 -0
  17. data/app/assets/stylesheets/decidim/admin/extra/_block_user.scss +5 -0
  18. data/app/assets/stylesheets/decidim/admin/extra/_title_bar.scss +1 -0
  19. data/app/assets/stylesheets/decidim/admin/modules/_moderations.scss +39 -0
  20. data/app/assets/stylesheets/decidim/admin/modules/_modules.scss +2 -0
  21. data/app/assets/stylesheets/decidim/admin/modules/_reveal.scss +5 -0
  22. data/app/assets/stylesheets/decidim/admin/modules/_secondary-nav.scss +6 -3
  23. data/app/assets/stylesheets/decidim/admin/modules/_user-login.scss +2 -2
  24. data/app/assets/stylesheets/decidim/admin/user_moderations.scss +3 -0
  25. data/app/assets/stylesheets/decidim/admin/utils/_settings.scss +1 -0
  26. data/app/cells/decidim/admin/content_block/show.erb +1 -1
  27. data/app/cells/decidim/admin/content_block_cell.rb +4 -0
  28. data/app/commands/decidim/admin/block_user.rb +70 -0
  29. data/app/commands/decidim/admin/create_import.rb +29 -0
  30. data/app/commands/decidim/admin/create_participatory_space_private_user.rb +1 -1
  31. data/app/commands/decidim/admin/create_static_page.rb +2 -1
  32. data/app/commands/decidim/admin/hide_resource.rb +21 -0
  33. data/app/commands/decidim/admin/impersonate_user.rb +17 -1
  34. data/app/commands/decidim/admin/promote_managed_user.rb +10 -0
  35. data/app/commands/decidim/admin/reorder_content_blocks.rb +6 -3
  36. data/app/commands/decidim/admin/transfer_user.rb +78 -0
  37. data/app/commands/decidim/admin/unblock_user.rb +48 -0
  38. data/app/commands/decidim/admin/unreport_user.rb +46 -0
  39. data/app/commands/decidim/admin/update_organization_appearance.rb +12 -4
  40. data/app/commands/decidim/admin/update_static_page.rb +2 -1
  41. data/app/commands/decidim/admin/verify_user_group.rb +1 -1
  42. data/app/controllers/concerns/decidim/admin/filterable.rb +1 -1
  43. data/app/controllers/concerns/decidim/admin/global_moderation_context.rb +47 -0
  44. data/app/controllers/concerns/decidim/admin/landing_page.rb +105 -0
  45. data/app/controllers/concerns/decidim/admin/landing_page_content_blocks.rb +118 -0
  46. data/app/controllers/concerns/decidim/moderations/admin/filterable.rb +54 -0
  47. data/app/controllers/decidim/admin/block_user_controller.rb +60 -0
  48. data/app/controllers/decidim/admin/components/base_controller.rb +1 -0
  49. data/app/controllers/decidim/admin/conflicts_controller.rb +46 -0
  50. data/app/controllers/decidim/admin/exports_controller.rb +1 -2
  51. data/app/controllers/decidim/admin/global_moderations/reports_controller.rb +18 -0
  52. data/app/controllers/decidim/admin/global_moderations_controller.rb +32 -0
  53. data/app/controllers/decidim/admin/impersonations_controller.rb +1 -1
  54. data/app/controllers/decidim/admin/imports_controller.rb +52 -0
  55. data/app/controllers/decidim/admin/moderated_users_controller.rb +44 -0
  56. data/app/controllers/decidim/admin/moderations/reports_controller.rb +39 -0
  57. data/app/controllers/decidim/admin/moderations_controller.rb +31 -7
  58. data/app/controllers/decidim/admin/officializations_controller.rb +3 -3
  59. data/app/controllers/decidim/admin/organization_homepage_controller.rb +6 -2
  60. data/app/controllers/decidim/admin/static_pages_controller.rb +7 -0
  61. data/app/events/decidim/resource_hidden_event.rb +37 -0
  62. data/app/forms/decidim/admin/block_user_form.rb +25 -0
  63. data/app/forms/decidim/admin/import_form.rb +85 -0
  64. data/app/forms/decidim/admin/organization_appearance_form.rb +1 -2
  65. data/app/forms/decidim/admin/static_page_form.rb +6 -1
  66. data/app/forms/decidim/admin/transfer_user_form.rb +19 -0
  67. data/app/helpers/decidim/admin/admin_terms_helper.rb +0 -7
  68. data/app/helpers/decidim/admin/application_helper.rb +5 -4
  69. data/app/helpers/decidim/admin/exports_helper.rb +2 -2
  70. data/app/helpers/decidim/admin/filterable_helper.rb +3 -2
  71. data/app/helpers/decidim/admin/imports_helper.rb +43 -0
  72. data/app/helpers/decidim/admin/menu_helper.rb +10 -0
  73. data/app/helpers/decidim/admin/moderations/reports_helper.rb +40 -0
  74. data/app/helpers/decidim/admin/moderations_helper.rb +36 -0
  75. data/app/helpers/decidim/admin/newsletters_helper.rb +4 -10
  76. data/app/helpers/decidim/admin/settings_helper.rb +2 -1
  77. data/app/helpers/decidim/admin/sidebar_menu_helper.rb +13 -0
  78. data/app/helpers/decidim/admin/user_moderations_helper.rb +6 -0
  79. data/app/jobs/decidim/admin/import_participatory_space_private_user_csv_job.rb +1 -1
  80. data/app/jobs/decidim/admin/verify_user_group_from_csv_job.rb +1 -1
  81. data/app/permissions/decidim/admin/permissions.rb +7 -6
  82. data/app/presenters/decidim/admin/dashboard_metric_charts_presenter.rb +1 -1
  83. data/app/presenters/decidim/admin/secondary_menu_presenter.rb +26 -0
  84. data/app/queries/decidim/admin/active_users_counter.rb +1 -2
  85. data/app/queries/decidim/admin/user_filter.rb +1 -2
  86. data/app/views/decidim/admin/admin_terms/show.html.erb +1 -1
  87. data/app/views/decidim/admin/area_types/index.html.erb +2 -2
  88. data/app/views/decidim/admin/areas/index.html.erb +1 -1
  89. data/app/views/decidim/admin/attachment_collections/index.html.erb +1 -1
  90. data/app/views/decidim/admin/attachments/index.html.erb +1 -1
  91. data/app/views/decidim/admin/block_user/new.html.erb +22 -0
  92. data/app/views/decidim/admin/categories/index.html.erb +1 -1
  93. data/app/views/decidim/admin/components/_component.html.erb +12 -0
  94. data/app/views/decidim/admin/conflicts/edit.html.erb +46 -0
  95. data/app/views/decidim/admin/conflicts/index.html.erb +34 -0
  96. data/app/views/decidim/admin/dashboard/show.html.erb +2 -1
  97. data/app/views/decidim/admin/exports/_dropdown.html.erb +1 -1
  98. data/app/views/decidim/admin/imports/_dropdown.html.erb +9 -0
  99. data/app/views/decidim/admin/imports/new.html.erb +57 -0
  100. data/app/views/decidim/admin/moderated_users/_report.html.erb +10 -0
  101. data/app/views/decidim/admin/moderated_users/index.html.erb +78 -0
  102. data/app/views/decidim/admin/moderations/_report.html.erb +1 -1
  103. data/app/views/decidim/admin/moderations/index.html.erb +28 -9
  104. data/app/views/decidim/admin/moderations/reports/index.html.erb +102 -0
  105. data/app/views/decidim/admin/moderations/reports/show.html.erb +62 -0
  106. data/app/views/decidim/admin/newsletters/index.html.erb +1 -1
  107. data/app/views/decidim/admin/newsletters/select_recipients_to_deliver.html.erb +3 -3
  108. data/app/views/decidim/admin/newsletters/show.html.erb +1 -1
  109. data/app/views/decidim/admin/officializations/index.html.erb +13 -4
  110. data/app/views/decidim/admin/organization_appearance/_form.html.erb +0 -4
  111. data/app/views/decidim/admin/organization_appearance/form/_colors.html.erb +1 -1
  112. data/app/views/decidim/admin/organization_appearance/form/_images.html.erb +4 -4
  113. data/app/views/decidim/admin/participatory_space_private_users/index.html.erb +1 -1
  114. data/app/views/decidim/admin/scopes/index.html.erb +1 -1
  115. data/app/views/decidim/admin/shared/landing_page/edit.html.erb +47 -0
  116. data/app/views/decidim/admin/shared/landing_page_content_blocks/edit.html.erb +15 -0
  117. data/app/views/decidim/admin/static_pages/_form.html.erb +6 -0
  118. data/app/views/decidim/admin/static_pages/_topic.html.erb +3 -3
  119. data/app/views/decidim/admin/users/index.html.erb +2 -2
  120. data/app/views/layouts/decidim/admin/_application.html.erb +6 -1
  121. data/app/views/layouts/decidim/admin/_js_configuration.html.erb +26 -0
  122. data/app/views/layouts/decidim/admin/_title_bar.html.erb +2 -2
  123. data/app/views/layouts/decidim/admin/global_moderations.html.erb +7 -0
  124. data/app/views/layouts/decidim/admin/newsletters.erb +1 -1
  125. data/app/views/layouts/decidim/admin/pages.html.erb +2 -2
  126. data/app/views/layouts/decidim/admin/settings.html.erb +2 -33
  127. data/app/views/layouts/decidim/admin/users.html.erb +11 -0
  128. data/config/locales/ar.yml +0 -5
  129. data/config/locales/bg.yml +0 -1
  130. data/config/locales/ca.yml +150 -4
  131. data/config/locales/cs.yml +151 -5
  132. data/config/locales/de.yml +150 -5
  133. data/config/locales/el.yml +55 -5
  134. data/config/locales/en.yml +151 -5
  135. data/config/locales/es-MX.yml +149 -3
  136. data/config/locales/es-PY.yml +149 -3
  137. data/config/locales/es.yml +149 -3
  138. data/config/locales/eu.yml +0 -3
  139. data/config/locales/fi-plain.yml +149 -3
  140. data/config/locales/fi.yml +149 -3
  141. data/config/locales/fr-CA.yml +146 -4
  142. data/config/locales/fr.yml +146 -4
  143. data/config/locales/gl.yml +120 -5
  144. data/config/locales/hu.yml +13 -5
  145. data/config/locales/id-ID.yml +0 -3
  146. data/config/locales/is-IS.yml +19 -3
  147. data/config/locales/it.yml +59 -5
  148. data/config/locales/ja.yml +59 -5
  149. data/config/locales/lv.yml +0 -5
  150. data/config/locales/nl.yml +113 -4
  151. data/config/locales/no.yml +11 -5
  152. data/config/locales/pl.yml +150 -5
  153. data/config/locales/pt-BR.yml +0 -3
  154. data/config/locales/pt.yml +0 -5
  155. data/config/locales/ro-RO.yml +102 -5
  156. data/config/locales/ru.yml +0 -3
  157. data/config/locales/sk.yml +0 -5
  158. data/config/locales/sl.yml +0 -1
  159. data/config/locales/sr-CS.yml +0 -3
  160. data/config/locales/sv.yml +149 -4
  161. data/config/locales/tr-TR.yml +81 -4
  162. data/config/locales/uk.yml +0 -3
  163. data/config/locales/zh-CN.yml +0 -5
  164. data/config/routes.rb +21 -1
  165. data/lib/decidim/admin.rb +6 -0
  166. data/lib/decidim/admin/engine.rb +76 -1
  167. data/lib/decidim/admin/import.rb +12 -0
  168. data/lib/decidim/admin/import/creator.rb +82 -0
  169. data/lib/decidim/admin/import/importer.rb +82 -0
  170. data/lib/decidim/admin/import/importer_factory.rb +17 -0
  171. data/lib/decidim/admin/import/readers.rb +39 -0
  172. data/lib/decidim/admin/import/readers/base.rb +31 -0
  173. data/lib/decidim/admin/import/readers/csv.rb +23 -0
  174. data/lib/decidim/admin/import/readers/json.rb +25 -0
  175. data/lib/decidim/admin/import/readers/xls.rb +25 -0
  176. data/lib/decidim/admin/test/commands/create_attachment_collection_examples.rb +6 -6
  177. data/lib/decidim/admin/test/commands/create_category_examples.rb +6 -6
  178. data/lib/decidim/admin/test/filterable_examples.rb +1 -8
  179. data/lib/decidim/admin/test/manage_moderations_examples.rb +68 -4
  180. data/lib/decidim/admin/version.rb +1 -1
  181. metadata +71 -15
  182. data/app/assets/javascripts/decidim/admin/gallery.js.es6 +0 -5
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Import
6
+ # This is an abstract class with a very naive default implementation
7
+ # for the importers to use. It can also serve as a superclass of your
8
+ # own implementation.
9
+ #
10
+ # It is used to be run against each element of an importable collection
11
+ # in order to parse relevant fields. Every import should specify their
12
+ # own creator or this default will be used.
13
+ class Creator
14
+ attr_reader :data
15
+
16
+ # Initializes the creator with a resource.
17
+ #
18
+ # data - The data hash to parse.
19
+ # context - The context needed by the producer
20
+ def initialize(data, context = nil)
21
+ @data = data.except(:id, "id")
22
+ @context = context
23
+ end
24
+
25
+ # Retuns the resource class to be created with the provided data.
26
+ def self.resource_klass
27
+ raise NotImplementedError, "#{self.class.name} does not define resource class"
28
+ end
29
+
30
+ # Can be used to convert the data hash to the resource attributes in
31
+ # case the data hash to be imported has different column names than the
32
+ # resource object to be created of it.
33
+ #
34
+ # By default returns the data hash but can be implemented by each creator
35
+ # implementation.
36
+ #
37
+ # Returns the resource attributes to be passed for the constructor.
38
+ def resource_attributes
39
+ @data
40
+ end
41
+
42
+ # Public: Returns a created object with the parsed data.
43
+ #
44
+ # Returns a target object.
45
+ def produce
46
+ self.class.resource_klass.new(resource_attributes)
47
+ end
48
+
49
+ def finish!
50
+ resource.save!
51
+ end
52
+
53
+ private
54
+
55
+ def resource
56
+ raise NotImplementedError, "#{self.class.name} does not define resource"
57
+ end
58
+
59
+ #
60
+ # Collect field's language specified cells to one hash
61
+ #
62
+ # field - The field name eg. "title"
63
+ # locales - Available locales
64
+ #
65
+ # Returns the hash including locale-imported_data pairs. eg. {en: "Heading", ca: "Cap", es: "Bóveda"}
66
+ #
67
+ def locale_hasher(field, locales)
68
+ return data[field.to_sym] if data.has_key?(field.to_sym)
69
+
70
+ hash = {}
71
+ locales.each do |locale|
72
+ parsed = data[:"#{field}/#{locale}"]
73
+ next if parsed.nil?
74
+
75
+ hash[locale] = parsed
76
+ end
77
+ hash
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Import
6
+ # Class providing the interface and implementation of an importer. Needs
7
+ # a reader to be passed to the constructor which handles the import file
8
+ # reading depending on its type.
9
+ #
10
+ # You can also use the ImporterFactory class to create an Importer
11
+ # instance.
12
+ class Importer
13
+ # Public: Initializes an Importer.
14
+ #
15
+ # file - A file with the data to be imported.
16
+ # reader - A Reader to be used to read the data from the file.
17
+ # creator - A Creator to be used during the import.
18
+ # context - A hash including component specific data.
19
+ def initialize(file:, reader: Readers::Base, creator: Creator, context: nil)
20
+ @file = file
21
+ @reader = reader
22
+ @creator = creator
23
+ @context = context
24
+ end
25
+
26
+ # Import data and create resources
27
+ #
28
+ # Returns an array of resources
29
+ def prepare
30
+ @prepare ||= collection.map(&:produce)
31
+ end
32
+
33
+ # Save resources
34
+ def import!
35
+ collection.map(&:finish!)
36
+ end
37
+
38
+ # Returns a collection of creators
39
+ def collection
40
+ @collection ||= collection_data.map { |item| creator.new(item, context) }
41
+ end
42
+
43
+ # Returns array of all resource indexes where validations fail.
44
+ def invalid_lines
45
+ @invalid_lines ||= check_invalid_lines(prepare)
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :file, :reader, :creator, :context
51
+
52
+ def collection_data
53
+ return @collection_data if @collection_data
54
+
55
+ @collection_data = []
56
+ data_headers = []
57
+ reader.new(file).read_rows do |rowdata, index|
58
+ if index.zero?
59
+ data_headers = rowdata.map(&:to_sym)
60
+ else
61
+ @collection_data << Hash[
62
+ rowdata.each_with_index.map do |val, ind|
63
+ [data_headers[ind], val]
64
+ end
65
+ ]
66
+ end
67
+ end
68
+
69
+ @collection_data
70
+ end
71
+
72
+ def check_invalid_lines(imported_data)
73
+ invalid_lines = []
74
+ imported_data.each_with_index do |record, index|
75
+ invalid_lines << index + 1 unless record.valid?
76
+ end
77
+ invalid_lines
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Import
6
+ # A factory class providing easier way to create new importers.
7
+ class ImporterFactory
8
+ def self.build(file, mime_type, **keyword_args)
9
+ reader = Readers.search_by_mime_type(mime_type)
10
+ raise NotImplementedError, "No reader implemented for mime type: #{mime_type}" if reader.nil?
11
+
12
+ Importer.new(file: file, reader: reader, **keyword_args)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Import
6
+ module Readers
7
+ autoload :Base, "decidim/admin/import/readers/base"
8
+ autoload :CSV, "decidim/admin/import/readers/csv"
9
+ autoload :JSON, "decidim/admin/import/readers/json"
10
+ autoload :XLS, "decidim/admin/import/readers/xls"
11
+
12
+ # Accepted mime types
13
+ # keys: are used for dynamic help text on admin form.
14
+ # values: are used to validate the file format of imported document.
15
+ ACCEPTED_MIME_TYPES = {
16
+ json: Readers::JSON::MIME_TYPE,
17
+ csv: Readers::CSV::MIME_TYPE,
18
+ xls: Readers::XLS::MIME_TYPE
19
+ }.freeze
20
+
21
+ def self.all
22
+ [
23
+ Readers::CSV,
24
+ Readers::JSON,
25
+ Readers::XLS
26
+ ]
27
+ end
28
+
29
+ def self.search_by_mime_type(mime_type)
30
+ all.each do |reader_klass|
31
+ return reader_klass if mime_type == reader_klass::MIME_TYPE
32
+ end
33
+
34
+ nil
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Import
6
+ module Readers
7
+ # Abstract class with a very naive default implementation. Each importable
8
+ # file type should have it's own reader.
9
+ class Base
10
+ def initialize(file)
11
+ @file = file
12
+ end
13
+
14
+ # The read_rows method should iterate over each row of the data and
15
+ # yield the data array of each row with the row's index.
16
+ # The first row yielded with index 0 needs to contain the data headers
17
+ # which can be later used to map the data to correct attributes.
18
+ #
19
+ # This needs to be implemented by the extending classes.
20
+ def read_rows
21
+ raise NotImplementedError
22
+ end
23
+
24
+ protected
25
+
26
+ attr_reader :file
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module Decidim
6
+ module Admin
7
+ module Import
8
+ module Readers
9
+ # Imports any exported CSV file to local objects. It transforms the
10
+ # import data using the creator into the final target objects.
11
+ class CSV < Base
12
+ MIME_TYPE = "text/csv"
13
+
14
+ def read_rows
15
+ ::CSV.read(file, col_sep: ";").each_with_index do |row, index|
16
+ yield row, index
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Decidim
6
+ module Admin
7
+ module Import
8
+ module Readers
9
+ # Imports any exported JSON file to local objects. It transforms the
10
+ # import data using the creator into the final target objects.
11
+ class JSON < Base
12
+ MIME_TYPE = "application/json"
13
+
14
+ def read_rows
15
+ json_string = File.read(file)
16
+ ::JSON.parse(json_string).each_with_index do |row, index|
17
+ yield row.keys, index if index.zero?
18
+ yield row.values, index + 1
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spreadsheet"
4
+
5
+ module Decidim
6
+ module Admin
7
+ module Import
8
+ module Readers
9
+ # Imports any exported XLS file to local objects. It transforms the
10
+ # import data using the creator into the final target objects.
11
+ class XLS < Base
12
+ MIME_TYPE = "application/vnd.ms-excel"
13
+
14
+ def read_rows
15
+ book = ::Spreadsheet.open(file)
16
+ sheet = book.worksheet(0)
17
+ sheet.each_with_index do |row, index|
18
+ yield row.to_a, index
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -10,12 +10,12 @@ module Decidim
10
10
  let(:form_params) do
11
11
  {
12
12
  "attachment_collection" => {
13
- "name_en" => Decidim::Faker::Localized.sentence(3),
14
- "name_es" => Decidim::Faker::Localized.sentence(3),
15
- "name_ca" => Decidim::Faker::Localized.sentence(3),
16
- "description_en" => Decidim::Faker::Localized.paragraph(3),
17
- "description_es" => Decidim::Faker::Localized.paragraph(3),
18
- "description_ca" => Decidim::Faker::Localized.paragraph(3)
13
+ "name_en" => Decidim::Faker::Localized.sentence(word_count: 3),
14
+ "name_es" => Decidim::Faker::Localized.sentence(word_count: 3),
15
+ "name_ca" => Decidim::Faker::Localized.sentence(word_count: 3),
16
+ "description_en" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
17
+ "description_es" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
18
+ "description_ca" => Decidim::Faker::Localized.paragraph(sentence_count: 3)
19
19
  }
20
20
  }
21
21
  end
@@ -10,12 +10,12 @@ module Decidim
10
10
  let(:form_params) do
11
11
  {
12
12
  "category" => {
13
- "name_en" => Decidim::Faker::Localized.paragraph(3),
14
- "name_es" => Decidim::Faker::Localized.paragraph(3),
15
- "name_ca" => Decidim::Faker::Localized.paragraph(3),
16
- "description_en" => Decidim::Faker::Localized.paragraph(3),
17
- "description_es" => Decidim::Faker::Localized.paragraph(3),
18
- "description_ca" => Decidim::Faker::Localized.paragraph(3)
13
+ "name_en" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
14
+ "name_es" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
15
+ "name_ca" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
16
+ "description_en" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
17
+ "description_es" => Decidim::Faker::Localized.paragraph(sentence_count: 3),
18
+ "description_ca" => Decidim::Faker::Localized.paragraph(sentence_count: 3)
19
19
  }
20
20
  }
21
21
  end
@@ -2,16 +2,9 @@
2
2
 
3
3
  shared_context "with filterable context" do
4
4
  let(:factory_name) { model_name.singular_route_key }
5
- let(:module_name) { model_name.route_key.camelize }
6
- let(:filterable_concern) { "Decidim::#{module_name}::Admin::Filterable".constantize }
7
-
8
- let(:filterable_fake_controller) do
9
- FILTERABLE_CONCERN ||= filterable_concern
10
- class FilterableFakeController < Decidim::ApplicationController; include FILTERABLE_CONCERN; end
11
- end
12
5
 
13
6
  def filterable_method(method_name)
14
- (@controller ||= filterable_fake_controller.new).send(method_name)
7
+ resource_controller.new.send(method_name)
15
8
  end
16
9
 
17
10
  def apply_filter(options, filter)
@@ -3,7 +3,7 @@
3
3
  shared_examples "manage moderations" do
4
4
  let!(:moderations) do
5
5
  reportables.first(reportables.length - 1).map do |reportable|
6
- moderation = create(:moderation, reportable: reportable, report_count: 1)
6
+ moderation = create(:moderation, reportable: reportable, report_count: 1, reported_content: reportable.reported_searchable_content_text)
7
7
  create(:report, moderation: moderation)
8
8
  moderation
9
9
  end
@@ -11,18 +11,29 @@ shared_examples "manage moderations" do
11
11
  let!(:moderation) { moderations.first }
12
12
  let!(:hidden_moderations) do
13
13
  reportables.last(1).map do |reportable|
14
- moderation = create(:moderation, reportable: reportable, report_count: 3, hidden_at: Time.current)
14
+ moderation = create(:moderation, reportable: reportable, report_count: 3, reported_content: reportable.reported_searchable_content_text, hidden_at: Time.current)
15
15
  create_list(:report, 3, moderation: moderation, reason: :spam)
16
16
  moderation
17
17
  end
18
18
  end
19
+ let(:moderations_link_text) { "Moderations" }
19
20
 
20
21
  before do
21
22
  visit participatory_space_path
22
- click_link "Moderations"
23
+ click_link moderations_link_text
23
24
  end
24
25
 
25
26
  context "when listing moderations" do
27
+ it "only lists moderations for the current organization" do
28
+ external_reportable = create :dummy_resource
29
+ external_moderation = create(:moderation, reportable: external_reportable, report_count: 1, reported_content: external_reportable.reported_searchable_content_text)
30
+ create(:report, moderation: external_moderation)
31
+
32
+ visit current_path
33
+
34
+ expect(page).to have_no_selector("tr[data-id=\"#{external_moderation.id}\"]")
35
+ end
36
+
26
37
  it "user can review them" do
27
38
  moderations.each do |moderation|
28
39
  within "tr[data-id=\"#{moderation.id}\"]" do
@@ -48,11 +59,64 @@ shared_examples "manage moderations" do
48
59
  expect(page).to have_admin_callout("Resource successfully hidden")
49
60
  expect(page).to have_no_content(moderation.reportable.reported_content_url)
50
61
  end
62
+
63
+ it "user can sort by report count" do
64
+ moderations.each_with_index { |moderation, index| moderation.update(report_count: index + 1) }
65
+ moderations_ordered_by_report_count_asc = moderations.sort_by(&:report_count)
66
+
67
+ within "table" do
68
+ click_link "Count"
69
+
70
+ all("tbody tr").each_with_index do |row, index|
71
+ reportable_id = moderations_ordered_by_report_count_asc[index].reportable.id
72
+ expect(row.find("td:first-child")).to have_content(reportable_id)
73
+ end
74
+ end
75
+ end
76
+
77
+ it "user can filter by reportable type" do
78
+ reportable_type = moderation.reportable.class.name.demodulize
79
+ within ".filters__section" do
80
+ find(:xpath, "//a[contains(text(), 'Filter')]").hover
81
+ find(:xpath, "//a[contains(text(), 'Type')]").hover
82
+ click_link reportable_type
83
+ end
84
+ expect(page).to have_selector("tbody tr", count: moderations.length)
85
+ end
86
+
87
+ it "user can filter by reported content" do
88
+ search = moderation.reportable.id
89
+ within ".filters__section" do
90
+ fill_in("Search Moderation by reportable id or content.", with: search)
91
+ find(:xpath, "//button[@type='submit']").click
92
+ end
93
+ expect(page).to have_selector("tbody tr", count: 1)
94
+ end
95
+
96
+ it "user can see moderation details" do
97
+ within "tr[data-id=\"#{moderation.id}\"]" do
98
+ click_link "Expand"
99
+ end
100
+
101
+ reported_content_slice = moderation.reportable.reported_searchable_content_text.split("\n").first
102
+ expect(page).to have_content(reported_content_slice)
103
+ end
104
+
105
+ context "when the reported content does not exist" do
106
+ it "still renders the page" do
107
+ moderation.reportable.destroy
108
+ visit current_path
109
+
110
+ expect(page).to have_no_selector("tr[data-id=\"#{moderation.id}\"]")
111
+ end
112
+ end
51
113
  end
52
114
 
53
115
  context "when listing hidden resources" do
54
116
  it "user can review them" do
55
- click_link "Hidden"
117
+ within ".card-title" do
118
+ click_link "Hidden"
119
+ end
56
120
 
57
121
  hidden_moderations.each do |moderation|
58
122
  within "tr[data-id=\"#{moderation.id}\"]" do