decidim-admin 0.23.5 → 0.24.2

Sign up to get free protection for your applications and to get access to all the features.

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