decidim-collaborative_texts 0.31.0.rc1

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.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +24 -0
  3. data/Rakefile +3 -0
  4. data/app/cells/decidim/collaborative_texts/document_cell.rb +23 -0
  5. data/app/cells/decidim/collaborative_texts/document_l_cell.rb +15 -0
  6. data/app/commands/decidim/collaborative_texts/admin/create_document.rb +25 -0
  7. data/app/commands/decidim/collaborative_texts/admin/publish_document.rb +52 -0
  8. data/app/commands/decidim/collaborative_texts/admin/unpublish_document.rb +44 -0
  9. data/app/commands/decidim/collaborative_texts/admin/update_document.rb +101 -0
  10. data/app/commands/decidim/collaborative_texts/admin/update_document_settings.rb +13 -0
  11. data/app/commands/decidim/collaborative_texts/create_suggestion.rb +28 -0
  12. data/app/commands/decidim/collaborative_texts/rollout.rb +50 -0
  13. data/app/controllers/concerns/decidim/collaborative_texts/admin/filterable.rb +23 -0
  14. data/app/controllers/decidim/collaborative_texts/admin/application_controller.rb +15 -0
  15. data/app/controllers/decidim/collaborative_texts/admin/documents_controller.rb +142 -0
  16. data/app/controllers/decidim/collaborative_texts/application_controller.rb +14 -0
  17. data/app/controllers/decidim/collaborative_texts/documents_controller.rb +57 -0
  18. data/app/controllers/decidim/collaborative_texts/suggestions_controller.rb +55 -0
  19. data/app/events/decidim/collaborative_texts/suggestion_accepted_event.rb +6 -0
  20. data/app/forms/decidim/collaborative_texts/admin/document_form.rb +29 -0
  21. data/app/forms/decidim/collaborative_texts/rollout_form.rb +26 -0
  22. data/app/forms/decidim/collaborative_texts/suggestion_form.rb +42 -0
  23. data/app/helpers/decidim/collaborative_texts/application_helper.rb +20 -0
  24. data/app/models/decidim/collaborative_texts/application_record.rb +10 -0
  25. data/app/models/decidim/collaborative_texts/document.rb +78 -0
  26. data/app/models/decidim/collaborative_texts/suggestion.rb +36 -0
  27. data/app/models/decidim/collaborative_texts/version.rb +35 -0
  28. data/app/packs/entrypoints/decidim_collaborative_texts.js +7 -0
  29. data/app/packs/images/decidim/collaborative_texts/decidim_collaborative_texts.svg +1 -0
  30. data/app/packs/src/decidim/collaborative_texts/document.js +168 -0
  31. data/app/packs/src/decidim/collaborative_texts/editor.js +80 -0
  32. data/app/packs/src/decidim/collaborative_texts/init_documents.js +27 -0
  33. data/app/packs/src/decidim/collaborative_texts/manager.js +106 -0
  34. data/app/packs/src/decidim/collaborative_texts/selection.js +106 -0
  35. data/app/packs/src/decidim/collaborative_texts/suggestion.js +243 -0
  36. data/app/packs/src/decidim/collaborative_texts/suggestions_list.js +103 -0
  37. data/app/packs/src/decidim/collaborative_texts/test/document.test.js +83 -0
  38. data/app/packs/src/decidim/collaborative_texts/test/manager.test.js +149 -0
  39. data/app/packs/src/decidim/collaborative_texts/test/selection.test.js +125 -0
  40. data/app/packs/src/decidim/collaborative_texts/test/suggestions.test.js +233 -0
  41. data/app/packs/src/decidim/collaborative_texts/test/toc.test.js +70 -0
  42. data/app/packs/src/decidim/collaborative_texts/toc.js +48 -0
  43. data/app/packs/stylesheets/decidim/collaborative_texts/collaborative_texts.scss +287 -0
  44. data/app/permissions/decidim/collaborative_texts/admin/permissions.rb +28 -0
  45. data/app/permissions/decidim/collaborative_texts/permissions.rb +36 -0
  46. data/app/presenters/decidim/collaborative_texts/admin_log/document_presenter.rb +54 -0
  47. data/app/presenters/decidim/collaborative_texts/admin_log/suggestion_presenter.rb +62 -0
  48. data/app/presenters/decidim/collaborative_texts/admin_log/suggestion_resource_presenter.rb +20 -0
  49. data/app/presenters/decidim/collaborative_texts/admin_log/version_presenter.rb +53 -0
  50. data/app/presenters/decidim/collaborative_texts/official_author_presenter.rb +11 -0
  51. data/app/presenters/decidim/collaborative_texts/suggestion_presenter.rb +57 -0
  52. data/app/views/decidim/collaborative_texts/admin/documents/_actions.html.erb +82 -0
  53. data/app/views/decidim/collaborative_texts/admin/documents/_document-tr.html.erb +15 -0
  54. data/app/views/decidim/collaborative_texts/admin/documents/_documents-thead.html.erb +7 -0
  55. data/app/views/decidim/collaborative_texts/admin/documents/_draft_options.html.erb +6 -0
  56. data/app/views/decidim/collaborative_texts/admin/documents/_form.html.erb +16 -0
  57. data/app/views/decidim/collaborative_texts/admin/documents/_non_draft_options.html.erb +9 -0
  58. data/app/views/decidim/collaborative_texts/admin/documents/_versions.html.erb +18 -0
  59. data/app/views/decidim/collaborative_texts/admin/documents/edit.html.erb +33 -0
  60. data/app/views/decidim/collaborative_texts/admin/documents/edit_settings.html.erb +18 -0
  61. data/app/views/decidim/collaborative_texts/admin/documents/index.html.erb +32 -0
  62. data/app/views/decidim/collaborative_texts/admin/documents/manage_trash.html.erb +19 -0
  63. data/app/views/decidim/collaborative_texts/admin/documents/new.html.erb +18 -0
  64. data/app/views/decidim/collaborative_texts/admin/settings/_form.html.erb +9 -0
  65. data/app/views/decidim/collaborative_texts/documents/_editor_template.html.erb +15 -0
  66. data/app/views/decidim/collaborative_texts/documents/_manager.html.erb +9 -0
  67. data/app/views/decidim/collaborative_texts/documents/_suggestions_box_item_template.html.erb +33 -0
  68. data/app/views/decidim/collaborative_texts/documents/_suggestions_box_template.html.erb +20 -0
  69. data/app/views/decidim/collaborative_texts/documents/index.html.erb +29 -0
  70. data/app/views/decidim/collaborative_texts/documents/show.html.erb +70 -0
  71. data/config/assets.rb +8 -0
  72. data/config/locales/am-ET.yml +1 -0
  73. data/config/locales/ar.yml +1 -0
  74. data/config/locales/bg.yml +1 -0
  75. data/config/locales/bn-BD.yml +1 -0
  76. data/config/locales/bs-BA.yml +1 -0
  77. data/config/locales/ca-IT.yml +154 -0
  78. data/config/locales/ca.yml +154 -0
  79. data/config/locales/cs.yml +122 -0
  80. data/config/locales/da.yml +1 -0
  81. data/config/locales/de.yml +154 -0
  82. data/config/locales/el.yml +1 -0
  83. data/config/locales/en.yml +154 -0
  84. data/config/locales/eo.yml +1 -0
  85. data/config/locales/es-MX.yml +154 -0
  86. data/config/locales/es-PY.yml +154 -0
  87. data/config/locales/es.yml +154 -0
  88. data/config/locales/et.yml +1 -0
  89. data/config/locales/eu.yml +154 -0
  90. data/config/locales/fa-IR.yml +1 -0
  91. data/config/locales/fi-plain.yml +154 -0
  92. data/config/locales/fi.yml +154 -0
  93. data/config/locales/fr-CA.yml +125 -0
  94. data/config/locales/fr.yml +125 -0
  95. data/config/locales/ga-IE.yml +1 -0
  96. data/config/locales/gl.yml +1 -0
  97. data/config/locales/gn-PY.yml +1 -0
  98. data/config/locales/he-IL.yml +1 -0
  99. data/config/locales/hr.yml +1 -0
  100. data/config/locales/hu.yml +1 -0
  101. data/config/locales/id-ID.yml +1 -0
  102. data/config/locales/is-IS.yml +1 -0
  103. data/config/locales/it.yml +1 -0
  104. data/config/locales/ja.yml +153 -0
  105. data/config/locales/ka-GE.yml +1 -0
  106. data/config/locales/kaa.yml +1 -0
  107. data/config/locales/ko.yml +1 -0
  108. data/config/locales/lb.yml +1 -0
  109. data/config/locales/lo-LA.yml +1 -0
  110. data/config/locales/lt.yml +1 -0
  111. data/config/locales/lv.yml +1 -0
  112. data/config/locales/mt.yml +1 -0
  113. data/config/locales/nl.yml +1 -0
  114. data/config/locales/no.yml +6 -0
  115. data/config/locales/oc-FR.yml +1 -0
  116. data/config/locales/om-ET.yml +1 -0
  117. data/config/locales/pl.yml +1 -0
  118. data/config/locales/pt-BR.yml +1 -0
  119. data/config/locales/pt.yml +1 -0
  120. data/config/locales/ro-RO.yml +89 -0
  121. data/config/locales/ru.yml +1 -0
  122. data/config/locales/si-LK.yml +1 -0
  123. data/config/locales/sk.yml +1 -0
  124. data/config/locales/sl.yml +1 -0
  125. data/config/locales/so-SO.yml +1 -0
  126. data/config/locales/sq-AL.yml +1 -0
  127. data/config/locales/sr-CS.yml +1 -0
  128. data/config/locales/sv.yml +117 -0
  129. data/config/locales/sw-KE.yml +1 -0
  130. data/config/locales/th-TH.yml +1 -0
  131. data/config/locales/ti-ER.yml +1 -0
  132. data/config/locales/tr-TR.yml +69 -0
  133. data/config/locales/uk.yml +1 -0
  134. data/config/locales/val-ES.yml +1 -0
  135. data/config/locales/vi.yml +1 -0
  136. data/config/locales/zh-CN.yml +1 -0
  137. data/config/locales/zh-TW.yml +1 -0
  138. data/db/migrate/20250205215038_create_decidim_collaborative_texts_documents.rb +16 -0
  139. data/db/migrate/20250213113536_create_collaborative_texts_versions.rb +13 -0
  140. data/db/migrate/20250227204839_create_collaborative_texts_suggestions.rb +13 -0
  141. data/db/migrate/20250312140133_add_counter_caches_to_collaborative_texts_documents.rb +13 -0
  142. data/db/migrate/20250408205231_add_counter_caches_to_collaborative_text_versions.rb +8 -0
  143. data/decidim-collaborative_texts.gemspec +36 -0
  144. data/lib/decidim/api/document_input_filter.rb +29 -0
  145. data/lib/decidim/api/document_input_sort.rb +14 -0
  146. data/lib/decidim/api/document_type.rb +31 -0
  147. data/lib/decidim/api/documents_type.rb +39 -0
  148. data/lib/decidim/api/suggestion_type.rb +18 -0
  149. data/lib/decidim/api/version_type.rb +21 -0
  150. data/lib/decidim/collaborative_texts/admin.rb +10 -0
  151. data/lib/decidim/collaborative_texts/admin_engine.rb +34 -0
  152. data/lib/decidim/collaborative_texts/api.rb +12 -0
  153. data/lib/decidim/collaborative_texts/component.rb +54 -0
  154. data/lib/decidim/collaborative_texts/engine.rb +28 -0
  155. data/lib/decidim/collaborative_texts/seeds.rb +117 -0
  156. data/lib/decidim/collaborative_texts/test/factories.rb +80 -0
  157. data/lib/decidim/collaborative_texts/version.rb +9 -0
  158. data/lib/decidim/collaborative_texts.rb +13 -0
  159. metadata +233 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class DocumentInputFilter < Decidim::Core::BaseInputFilter
6
+ include Decidim::Core::HasTimestampInputFilter
7
+
8
+ graphql_name "CollaborativeTextFilter"
9
+ description "A type used for filtering collaborative texts inside a participatory space.
10
+
11
+ A typical query would look like:
12
+
13
+ ```
14
+ {
15
+ participatoryProcesses {
16
+ components {
17
+ ...on CollaborativeTexts {
18
+ collaborativeTexts(filter:{ createdBefore: \"2020-01-01\" }) {
19
+ id
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ ```
26
+ "
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class DocumentInputSort < Decidim::Core::BaseInputSort
6
+ include Decidim::Core::HasTimestampInputSort
7
+
8
+ graphql_name "CollaborativeTextSort"
9
+ description "A type used for sorting blog collaborative texts"
10
+
11
+ argument :id, GraphQL::Types::String, "Sort by ID, valid values are ASC or DESC", required: false
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class DocumentType < Decidim::Api::Types::BaseObject
6
+ graphql_name "CollaborativeText"
7
+ description "A collaborative text document."
8
+
9
+ implements Decidim::Core::CoauthorableInterface
10
+ implements Decidim::Core::TraceableInterface
11
+ implements Decidim::Core::TimestampsInterface
12
+
13
+ field :accepting_suggestions, GraphQL::Types::Boolean, "Whether this collaborative text document is accepting suggestions or not", null: true
14
+ field :announcement, Decidim::Core::TranslatedFieldType, "The announcement of this collaborative text document.", null: true
15
+ field :body, GraphQL::Types::String, "The body of this collaborative text document.", null: true
16
+ field :document_versions, [Decidim::CollaborativeTexts::VersionType], "The versions of this collaborative text document.", null: true
17
+ field :document_versions_count, GraphQL::Types::Int, "The number of versions for this collaborative text document.", null: true
18
+ field :draft, GraphQL::Types::Boolean, "Whether this collaborative text document is a draft or not", null: true
19
+ field :id, GraphQL::Types::ID, "The id of the collaborative text document", null: false
20
+ field :published_at, Decidim::Core::DateTimeType, description: "The date and time this collaborative text document was published", null: true
21
+ field :suggestions, [Decidim::CollaborativeTexts::SuggestionType], "The suggestions for this collaborative text document.", null: true
22
+ field :suggestions_count, GraphQL::Types::Int, "The number of suggestions for this collaborative text document.", null: true
23
+ field :title, GraphQL::Types::String, "The title of this collaborative text document.", null: false
24
+ field :url, String, "The URL for this project", null: false
25
+
26
+ def url
27
+ Decidim::ResourceLocatorPresenter.new(object).url
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class DocumentsType < Decidim::Core::ComponentType
6
+ graphql_name "CollaborativeTexts"
7
+ description "A collaborative texts component of a participatory space."
8
+
9
+ field :collaborative_text, Decidim::CollaborativeTexts::DocumentType, "A single CollaborativeText object", null: true do
10
+ argument :id, GraphQL::Types::ID, "The id of the CollaborativeText requested", required: true
11
+ end
12
+
13
+ field :collaborative_texts, Decidim::CollaborativeTexts::DocumentType.connection_type, "A collection of CollaborativeTexts", null: false, connection: true do
14
+ argument :filter, Decidim::CollaborativeTexts::DocumentInputFilter, "Provides several methods to filter the results", required: false
15
+ argument :order, Decidim::CollaborativeTexts::DocumentInputSort, "Provides several methods to order the results", required: false
16
+ end
17
+
18
+ def collaborative_texts(filter: {}, order: {})
19
+ base_query = Decidim::Core::ComponentListBase.new(model_class: Document).call(object, { filter:, order: }, context)
20
+ if context[:current_user]&.admin?
21
+ base_query
22
+ else
23
+ base_query.published
24
+ end
25
+ end
26
+
27
+ def collaborative_text(id:)
28
+ scope =
29
+ if context[:current_user]&.admin?
30
+ Document
31
+ else
32
+ Document.published
33
+ end
34
+
35
+ Decidim::Core::ComponentFinderBase.new(model_class: scope).call(object, { id: }, context)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class SuggestionType < Decidim::Api::Types::BaseObject
6
+ description "A suggestion for a collaborative text document version."
7
+
8
+ implements Decidim::Core::TraceableInterface
9
+ implements Decidim::Core::TimestampsInterface
10
+ implements Decidim::Core::AuthorableInterface
11
+
12
+ field :changeset, GraphQL::Types::JSON, "The changeset of this suggestion", null: false
13
+ field :document_version, Decidim::CollaborativeTexts::VersionType, "The version this suggestion belongs to", null: false
14
+ field :id, GraphQL::Types::ID, "The id of the suggestion", null: false
15
+ field :status, GraphQL::Types::String, "The status of the suggestion", null: false
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class VersionType < Decidim::Api::Types::BaseObject
6
+ graphql_name "DocumentVersion"
7
+ description "A specific version for a collaborative text document."
8
+
9
+ implements Decidim::Core::TraceableInterface
10
+ implements Decidim::Core::TimestampsInterface
11
+
12
+ field :body, GraphQL::Types::String, "The body of this collaborative text document version.", null: true
13
+ field :document, Decidim::CollaborativeTexts::DocumentType, "The collaborative text document this version belongs to.", null: true
14
+ field :draft, GraphQL::Types::Boolean, "Whether this collaborative text document version is a draft or not", null: true
15
+ field :id, GraphQL::Types::ID, "The id of the collaborative text document version", null: false
16
+ field :suggestions, [Decidim::CollaborativeTexts::SuggestionType, { null: true }], "The suggestions for this collaborative text document version.", null: true
17
+ field :suggestions_count, GraphQL::Types::Int, "The number of suggestions for this collaborative text document version.", null: true
18
+ field :title, GraphQL::Types::String, "The title of this collaborative text document version.", null: false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ # This module contains all the domain logic associated to Decidim's
6
+ # CollaborativeTexts participatory space admin panel.
7
+ module Admin
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ # This is the engine that runs on the public interface of `decidim-collaborative_texts`.
6
+ class AdminEngine < ::Rails::Engine
7
+ isolate_namespace Decidim::CollaborativeTexts::Admin
8
+
9
+ paths["db/migrate"] = nil
10
+ paths["lib/tasks"] = nil
11
+
12
+ routes do
13
+ resources :documents, except: [:destroy], controller: "documents" do
14
+ member do
15
+ patch :soft_delete
16
+ patch :restore
17
+ put :publish
18
+ put :unpublish
19
+ get :edit_settings
20
+ patch :update_settings
21
+ end
22
+
23
+ get :manage_trash, on: :collection
24
+ end
25
+
26
+ root to: "documents#index"
27
+ end
28
+
29
+ def load_seed
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ autoload :DocumentsType, "decidim/api/documents_type"
6
+ autoload :DocumentInputFilter, "decidim/api/document_input_filter"
7
+ autoload :DocumentInputSort, "decidim/api/document_input_sort"
8
+ autoload :DocumentType, "decidim/api/document_type"
9
+ autoload :VersionType, "decidim/api/version_type"
10
+ autoload :SuggestionType, "decidim/api/suggestion_type"
11
+ end
12
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ Decidim.register_component(:collaborative_texts) do |component|
4
+ component.engine = Decidim::CollaborativeTexts::Engine
5
+ component.admin_engine = Decidim::CollaborativeTexts::AdminEngine
6
+ component.icon = "media/images/decidim_collaborative_texts.svg"
7
+ component.icon_key = "draft-line"
8
+ component.permissions_class_name = "Decidim::CollaborativeTexts::Permissions"
9
+
10
+ component.query_type = "Decidim::CollaborativeTexts::DocumentsType"
11
+
12
+ component.register_stat :collaborative_texts_count,
13
+ primary: true,
14
+ priority: Decidim::StatsRegistry::MEDIUM_PRIORITY,
15
+ icon_name: "draft-line",
16
+ tooltip_key: "collaborative_texts_count_tooltip" do |components, start_at, end_at|
17
+ collaborative_texts = Decidim::CollaborativeTexts::Document.where(component: components).published
18
+ collaborative_texts = collaborative_texts.where(created_at: start_at..) if start_at.present?
19
+ collaborative_texts = collaborative_texts.where(created_at: ..end_at) if end_at.present?
20
+ collaborative_texts.count
21
+ end
22
+
23
+ # For the admin sidebar (primary: true)
24
+ component.register_stat :all_collaborative_texts_count, primary: true, priority: Decidim::StatsRegistry::LOW_PRIORITY do |components, start_at, end_at|
25
+ collaborative_texts = Decidim::CollaborativeTexts::Document.where(component: components)
26
+ collaborative_texts = collaborative_texts.where(created_at: start_at..) if start_at.present?
27
+ collaborative_texts = collaborative_texts.where(created_at: ..end_at) if end_at.present?
28
+ collaborative_texts.count
29
+ end
30
+
31
+ component.actions = %w(create update destroy)
32
+
33
+ component.settings(:global) do |settings|
34
+ settings.attribute :announcement, type: :text, translated: true, editor: true
35
+ end
36
+
37
+ component.settings(:step) do |settings|
38
+ settings.attribute :announcement, type: :text, translated: true, editor: true
39
+ end
40
+
41
+ component.register_resource(:collaborative_text) do |resource|
42
+ resource.model_class_name = "Decidim::CollaborativeTexts::Document"
43
+ resource.card = "decidim/collaborative_texts/document"
44
+ resource.searchable = true
45
+ end
46
+
47
+ # component.exports ...
48
+
49
+ component.seeds do |participatory_space|
50
+ require "decidim/collaborative_texts/seeds"
51
+
52
+ Decidim::CollaborativeTexts::Seeds.new(participatory_space:).call
53
+ end
54
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Decidim::CollaborativeTexts
7
+
8
+ routes do
9
+ resources :documents do
10
+ resources :suggestions
11
+ end
12
+ scope "/documents" do
13
+ root to: "documents#index"
14
+ end
15
+ get "/", to: redirect("documents", status: 301)
16
+ end
17
+
18
+ initializer "decidim_collaborative_texts.shakapacker.assets_path" do
19
+ Decidim.register_assets_path File.expand_path("app/packs", root)
20
+ end
21
+
22
+ initializer "decidim_collaborative_texts.add_cells_view_paths" do
23
+ Cell::ViewModel.view_paths << File.expand_path("#{Decidim::CollaborativeTexts::Engine.root}/app/cells")
24
+ Cell::ViewModel.view_paths << File.expand_path("#{Decidim::CollaborativeTexts::Engine.root}/app/views") # for partials
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/components/namer"
4
+ require "decidim/seeds"
5
+
6
+ module Decidim
7
+ module CollaborativeTexts
8
+ class Seeds < Decidim::Seeds
9
+ attr_reader :participatory_space
10
+
11
+ def initialize(participatory_space:)
12
+ @participatory_space = participatory_space
13
+ end
14
+
15
+ def call
16
+ component = create_component!
17
+
18
+ number_of_records.times do
19
+ create_document!(component:)
20
+ end
21
+
22
+ number_of_records.times do
23
+ create_document!(component:, published_at: nil)
24
+ end
25
+ end
26
+
27
+ def create_component!
28
+ params = {
29
+ name: Decidim::Components::Namer.new(participatory_space.organization.available_locales, :collaborative_texts).i18n_name,
30
+ manifest_name: :collaborative_texts,
31
+ published_at: Time.current,
32
+ participatory_space: participatory_space
33
+ }
34
+
35
+ Decidim.traceability.perform_action!(
36
+ "publish",
37
+ Decidim::Component,
38
+ admin_user,
39
+ visibility: "all"
40
+ ) do
41
+ Decidim::Component.create!(params)
42
+ end
43
+ end
44
+
45
+ def create_document!(component:, published_at: Time.current)
46
+ body_blocks = create_body_blocks
47
+ params = {
48
+ component:,
49
+ title: ::Faker::Lorem.paragraph,
50
+ body: body_blocks.join("\n"),
51
+ published_at:,
52
+ accepting_suggestions: [true, false].sample,
53
+ coauthorships: [Decidim::Coauthorship.new(author: organization)]
54
+ }
55
+
56
+ document = Decidim.traceability.create!(
57
+ Decidim::CollaborativeTexts::Document,
58
+ admin_user,
59
+ params,
60
+ visibility: "all"
61
+ )
62
+
63
+ # Create some versions
64
+ number_of_records.times do |num|
65
+ params = {
66
+ document:,
67
+ body: create_body_blocks.join("\n"),
68
+ created_at: num.seconds.from_now
69
+ }
70
+ Decidim.traceability.create!(
71
+ Decidim::CollaborativeTexts::Version,
72
+ admin_user,
73
+ params,
74
+ visibility: "all"
75
+ )
76
+ end
77
+
78
+ # Create some suggestions
79
+ random_positions = (0...body_blocks.size).to_a.sample(5)
80
+ random_positions.each do |position|
81
+ changeset = {
82
+ firstNode: position.to_s,
83
+ lastNode: (position + rand(1..3)).to_s,
84
+ replace: rand(1..4).times.map { ::Faker::HTML.paragraph(sentence_count: rand(1..3)) }
85
+ }
86
+ create_suggestion!(document_version: document.current_version, changeset:)
87
+ end
88
+
89
+ document
90
+ end
91
+
92
+ def create_suggestion!(document_version:, changeset:)
93
+ params = {
94
+ document_version:,
95
+ changeset:,
96
+ author: document_version.organization.users.sample
97
+ }
98
+ Decidim::CollaborativeTexts::Suggestion.create!(params)
99
+ end
100
+
101
+ def create_body_blocks
102
+ blocks = []
103
+ rand(3..5).times do
104
+ blocks << "<h2>#{::Faker::Lorem.word.capitalize}</h2>"
105
+ level = 3
106
+ rand(1..4).times do
107
+ blocks << "<h#{level}>#{::Faker::Lorem.word.capitalize}</h#{level}>"
108
+ blocks << ::Faker::HTML.paragraph(sentence_count: rand(3..5))
109
+ blocks << ::Faker::HTML.random(exclude: [:heading, :script, :table])
110
+ level += 1
111
+ end
112
+ end
113
+ blocks
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/components/namer"
4
+ require "decidim/core/test/factories"
5
+ require "decidim/participatory_processes/test/factories"
6
+
7
+ FactoryBot.define do
8
+ factory :collaborative_text_component, parent: :component do
9
+ transient do
10
+ skip_injection { false }
11
+ end
12
+
13
+ name { generate_component_name(participatory_space.organization.available_locales, :collaborative_texts, skip_injection:) }
14
+ manifest_name { :collaborative_texts }
15
+ participatory_space { create(:participatory_process, :with_steps, skip_injection:, organization:) }
16
+ end
17
+
18
+ factory :collaborative_text_document, class: "Decidim::CollaborativeTexts::Document" do
19
+ transient do
20
+ users { nil }
21
+ skip_injection { false }
22
+ end
23
+ title { generate_title(:collaborative_text_document_title, skip_injection:) }
24
+ component { create(:collaborative_text_component, skip_injection:) }
25
+
26
+ trait :with_body do
27
+ body { Faker::HTML.paragraph }
28
+ end
29
+
30
+ trait :with_versions do
31
+ document_versions { build_list(:collaborative_text_version, 3) }
32
+ end
33
+
34
+ trait :published do
35
+ published_at { Time.current }
36
+ end
37
+
38
+ after :build do |document, evaluator|
39
+ if document.component
40
+ users = evaluator.users || [document.component.organization]
41
+ users.each do |user|
42
+ document.coauthorships.build(author: user)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ factory :collaborative_text_version, class: "Decidim::CollaborativeTexts::Version" do
49
+ body { Faker::HTML.paragraph }
50
+ document { create(:collaborative_text_document) }
51
+ draft { false }
52
+
53
+ trait :draft do
54
+ draft { true }
55
+ end
56
+ end
57
+
58
+ factory :collaborative_text_suggestion, class: "Decidim::CollaborativeTexts::Suggestion" do
59
+ document_version { build(:collaborative_text_version) }
60
+ author { build(:user, :confirmed, organization: document_version.document.organization) }
61
+ trait :pending do
62
+ status { :pending }
63
+ end
64
+ trait :accepted do
65
+ status { :accepted }
66
+ end
67
+ trait :rejected do
68
+ status { :rejected }
69
+ end
70
+
71
+ changeset do
72
+ {
73
+ firstNode: "1",
74
+ lastNode: "2",
75
+ original: [Faker::HTML.paragraph(sentence_count: rand(1..3))],
76
+ replace: [Faker::HTML.paragraph(sentence_count: rand(1..3))]
77
+ }
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module CollaborativeTexts
5
+ def self.version
6
+ "0.31.0.rc1"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/collaborative_texts/admin"
4
+ require "decidim/collaborative_texts/api"
5
+ require "decidim/collaborative_texts/engine"
6
+ require "decidim/collaborative_texts/admin_engine"
7
+ require "decidim/collaborative_texts/component"
8
+
9
+ module Decidim
10
+ # Base module for the collaborative_texts engine.
11
+ module CollaborativeTexts
12
+ end
13
+ end