decidim-proposals 0.14.4 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -0
  3. data/app/assets/images/decidim/gamification/badges/accepted_proposals.svg +194 -104
  4. data/app/assets/images/decidim/gamification/badges/proposals.svg +192 -108
  5. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +25 -20
  6. data/app/cells/decidim/proposals/proposal_activity_cell.rb +19 -0
  7. data/app/commands/decidim/proposals/admin/answer_proposal.rb +6 -2
  8. data/app/commands/decidim/proposals/admin/create_proposal.rb +4 -4
  9. data/app/commands/decidim/proposals/admin/import_participatory_text.rb +49 -0
  10. data/app/commands/decidim/proposals/admin/import_proposals.rb +7 -21
  11. data/app/commands/decidim/proposals/admin/merge_proposals.rb +68 -0
  12. data/app/commands/decidim/proposals/admin/publish_participatory_text.rb +65 -0
  13. data/app/commands/decidim/proposals/admin/split_proposals.rb +67 -0
  14. data/app/commands/decidim/proposals/admin/update_proposal.rb +67 -0
  15. data/app/commands/decidim/proposals/create_collaborative_draft.rb +19 -14
  16. data/app/commands/decidim/proposals/create_proposal.rb +4 -2
  17. data/app/commands/decidim/proposals/endorse_proposal.rb +5 -1
  18. data/app/commands/decidim/proposals/publish_proposal.rb +15 -3
  19. data/app/commands/decidim/proposals/unvote_proposal.rb +34 -3
  20. data/app/commands/decidim/proposals/vote_proposal.rb +32 -2
  21. data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +62 -0
  22. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +28 -1
  23. data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +27 -0
  24. data/app/controllers/decidim/proposals/admin/proposals_splits_controller.rb +27 -0
  25. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +0 -1
  26. data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +6 -2
  27. data/app/controllers/decidim/proposals/proposal_votes_controller.rb +15 -0
  28. data/app/controllers/decidim/proposals/proposals_controller.rb +1 -1
  29. data/app/forms/decidim/proposals/admin/import_participatory_text_form.rb +28 -0
  30. data/app/forms/decidim/proposals/admin/preview_participatory_text_form.rb +21 -0
  31. data/app/forms/decidim/proposals/admin/proposal_form.rb +4 -1
  32. data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +57 -0
  33. data/app/forms/decidim/proposals/admin/proposals_merge_form.rb +13 -0
  34. data/app/forms/decidim/proposals/admin/proposals_split_form.rb +12 -0
  35. data/app/helpers/decidim/proposals/application_helper.rb +23 -0
  36. data/app/helpers/decidim/proposals/map_helper.rb +1 -1
  37. data/app/helpers/decidim/proposals/participatory_texts_helper.rb +18 -0
  38. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +1 -1
  39. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +2 -1
  40. data/app/jobs/decidim/proposals/notify_proposals_mentioned_job.rb +3 -4
  41. data/app/models/decidim/proposals/participatory_text.rb +13 -0
  42. data/app/models/decidim/proposals/proposal.rb +31 -9
  43. data/app/models/decidim/proposals/proposal_vote.rb +21 -1
  44. data/app/permissions/decidim/proposals/admin/permissions.rb +30 -0
  45. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +5 -1
  46. data/app/presenters/decidim/proposals/log/resource_presenter.rb +18 -0
  47. data/app/presenters/decidim/proposals/official_author_presenter.rb +4 -0
  48. data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +29 -0
  49. data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +53 -0
  50. data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +57 -0
  51. data/app/services/decidim/proposals/proposal_builder.rb +72 -0
  52. data/app/services/decidim/proposals/proposal_search.rb +2 -2
  53. data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +13 -0
  54. data/app/views/decidim/proposals/admin/participatory_texts/_bulk-actions.html.erb +1 -0
  55. data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +43 -0
  56. data/app/views/decidim/proposals/admin/participatory_texts/new_import.html.erb +39 -0
  57. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +7 -2
  58. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +4 -0
  59. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +36 -0
  60. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_merge.html.erb +15 -0
  61. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_recategorize.html.erb +15 -0
  62. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_split.html.erb +15 -0
  63. data/app/views/decidim/proposals/admin/proposals/edit.html.erb +7 -0
  64. data/app/views/decidim/proposals/admin/proposals/index.html.erb +2 -2
  65. data/app/views/decidim/proposals/collaborative_drafts/compare.html.erb +2 -2
  66. data/app/views/decidim/proposals/collaborative_drafts/complete.html.erb +1 -1
  67. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -1
  68. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +5 -1
  69. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +1 -1
  70. data/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +13 -4
  71. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +2 -2
  72. data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +1 -1
  73. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +1 -1
  74. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +15 -4
  75. data/app/views/decidim/proposals/proposals/new.html.erb +1 -1
  76. data/config/locales/ca.yml +72 -4
  77. data/config/locales/de.yml +71 -3
  78. data/config/locales/en.yml +71 -3
  79. data/config/locales/es-PY.yml +71 -3
  80. data/config/locales/es.yml +73 -5
  81. data/config/locales/eu.yml +71 -3
  82. data/config/locales/fi.yml +81 -13
  83. data/config/locales/fr.yml +71 -3
  84. data/config/locales/gl.yml +71 -3
  85. data/config/locales/hu.yml +71 -3
  86. data/config/locales/it.yml +71 -3
  87. data/config/locales/nl.yml +71 -3
  88. data/config/locales/pl.yml +71 -3
  89. data/config/locales/pt-BR.yml +72 -4
  90. data/config/locales/pt.yml +71 -3
  91. data/config/locales/sv.yml +71 -3
  92. data/db/migrate/20180927111721_create_participatory_texts.rb +13 -0
  93. data/db/migrate/20180930125321_add_participatory_text_level_to_proposals.rb +7 -0
  94. data/db/migrate/20180930125321_add_position_to_proposals.rb +7 -0
  95. data/db/migrate/20181003074440_fix_user_groups_ids_in_proposals_endorsements.rb +16 -0
  96. data/db/migrate/20181010114622_add_temporary_votes.rb +9 -0
  97. data/db/migrate/20181016132225_add_organization_as_author.rb +13 -0
  98. data/db/migrate/20181017084221_make_author_polymorhpic_for_proposal_endorsements.rb +31 -0
  99. data/lib/decidim/content_parsers/proposal_parser.rb +9 -3
  100. data/lib/decidim/proposals.rb +3 -1
  101. data/lib/decidim/proposals/admin_engine.rb +12 -1
  102. data/lib/decidim/proposals/component.rb +60 -23
  103. data/lib/decidim/proposals/engine.rb +55 -12
  104. data/lib/decidim/proposals/markdown_to_proposals.rb +90 -0
  105. data/lib/decidim/proposals/participatory_text_section.rb +21 -0
  106. data/lib/decidim/proposals/test/factories.rb +35 -7
  107. data/lib/decidim/proposals/version.rb +1 -1
  108. metadata +86 -19
@@ -4,6 +4,7 @@ require "decidim/proposals/admin"
4
4
  require "decidim/proposals/engine"
5
5
  require "decidim/proposals/admin_engine"
6
6
  require "decidim/proposals/component"
7
+ require "acts_as_list"
7
8
 
8
9
  module Decidim
9
10
  # This namespace holds the logic of the `Proposals` component. This component
@@ -12,7 +13,8 @@ module Decidim
12
13
  autoload :ProposalSerializer, "decidim/proposals/proposal_serializer"
13
14
  autoload :CommentableProposal, "decidim/proposals/commentable_proposal"
14
15
  autoload :CommentableCollaborativeDraft, "decidim/proposals/commentable_collaborative_draft"
15
- autoload :ViewModel, "decidim/proposals/view_model"
16
+ autoload :MarkdownToProposals, "decidim/proposals/markdown_to_proposals"
17
+ autoload :ParticipatoryTextSection, "decidim/proposals/participatory_text_section"
16
18
 
17
19
  include ActiveSupport::Configurable
18
20
 
@@ -10,14 +10,25 @@ module Decidim
10
10
  paths["lib/tasks"] = nil
11
11
 
12
12
  routes do
13
- resources :proposals, only: [:index, :new, :create] do
13
+ resources :proposals, only: [:index, :new, :create, :edit, :update] do
14
14
  post :update_category, on: :collection
15
15
  collection do
16
16
  resource :proposals_import, only: [:new, :create]
17
+ resource :proposals_merge, only: [:create]
18
+ resource :proposals_split, only: [:create]
17
19
  end
18
20
  resources :proposal_answers, only: [:edit, :update]
19
21
  resources :proposal_notes, only: [:index, :create]
20
22
  end
23
+ scope "/proposal_components/:component_id" do
24
+ resources :participatory_texts, only: :index do
25
+ collection do
26
+ get :new_import
27
+ post :import
28
+ post :publish
29
+ end
30
+ end
31
+ end
21
32
 
22
33
  root to: "proposals#index"
23
34
  end
@@ -21,6 +21,7 @@ Decidim.register_component(:proposals) do |component|
21
21
 
22
22
  component.settings(:global) do |settings|
23
23
  settings.attribute :vote_limit, type: :integer, default: 0
24
+ settings.attribute :minimum_votes_per_user, type: :integer, default: 0
24
25
  settings.attribute :proposal_limit, type: :integer, default: 0
25
26
  settings.attribute :proposal_length, type: :integer, default: 500
26
27
  settings.attribute :proposal_edit_before_minutes, type: :integer, default: 5
@@ -33,6 +34,7 @@ Decidim.register_component(:proposals) do |component|
33
34
  settings.attribute :attachments_allowed, type: :boolean, default: false
34
35
  settings.attribute :resources_permissions_enabled, type: :boolean, default: true
35
36
  settings.attribute :collaborative_drafts_enabled, type: :boolean, default: false
37
+ settings.attribute :participatory_texts_enabled, type: :boolean, default: false
36
38
  settings.attribute :announcement, type: :text, translated: true, editor: true
37
39
  settings.attribute :new_proposal_help_text, type: :text, translated: true, editor: true
38
40
  settings.attribute :proposal_wizard_step_1_help_text, type: :text, translated: true, editor: true
@@ -110,13 +112,18 @@ Decidim.register_component(:proposals) do |component|
110
112
  end
111
113
 
112
114
  component.seeds do |participatory_space|
115
+ admin_user = Decidim::User.find_by(
116
+ organization: participatory_space.organization,
117
+ email: "admin@example.org"
118
+ )
119
+
113
120
  step_settings = if participatory_space.allows_steps?
114
121
  { participatory_space.active_step.id => { votes_enabled: true, votes_blocked: false, creation_enabled: true } }
115
122
  else
116
123
  {}
117
124
  end
118
125
 
119
- component = Decidim::Component.create!(
126
+ params = {
120
127
  name: Decidim::Components::Namer.new(participatory_space.organization.available_locales, :proposals).i18n_name,
121
128
  manifest_name: :proposals,
122
129
  published_at: Time.current,
@@ -126,7 +133,16 @@ Decidim.register_component(:proposals) do |component|
126
133
  collaborative_drafts_enabled: true
127
134
  },
128
135
  step_settings: step_settings
129
- )
136
+ }
137
+
138
+ component = Decidim.traceability.perform_action!(
139
+ "publish",
140
+ Decidim::Component,
141
+ admin_user,
142
+ visibility: "all"
143
+ ) do
144
+ Decidim::Component.create!(params)
145
+ end
130
146
 
131
147
  if participatory_space.scope
132
148
  scopes = participatory_space.scope.descendants
@@ -147,7 +163,7 @@ Decidim.register_component(:proposals) do |component|
147
163
  [nil, nil]
148
164
  end
149
165
 
150
- proposal = Decidim::Proposals::Proposal.create!(
166
+ params = {
151
167
  component: component,
152
168
  category: participatory_space.categories.sample,
153
169
  scope: Faker::Boolean.boolean(0.5) ? global : scopes.sample,
@@ -157,10 +173,23 @@ Decidim.register_component(:proposals) do |component|
157
173
  answer: answer,
158
174
  answered_at: Time.current,
159
175
  published_at: Time.current
160
- )
176
+ }
177
+
178
+ proposal = Decidim.traceability.perform_action!(
179
+ "publish",
180
+ Decidim::Proposals::Proposal,
181
+ admin_user,
182
+ visibility: "all"
183
+ ) do
184
+ proposal = Decidim::Proposals::Proposal.new(params)
185
+ proposal.add_coauthor(participatory_space.organization)
186
+ proposal.save!
187
+ proposal
188
+ end
189
+
161
190
  if n.positive?
162
191
  Decidim::User.where(decidim_organization_id: participatory_space.decidim_organization_id).all.sample(n).each do |author|
163
- user_group = [true, false].sample ? author.user_groups.verified.sample : nil
192
+ user_group = [true, false].sample ? Decidim::UserGroups::ManageableUserGroups.for(author).verified.sample : nil
164
193
  proposal.add_coauthor(author, user_group: user_group)
165
194
  end
166
195
  end
@@ -203,13 +232,19 @@ Decidim.register_component(:proposals) do |component|
203
232
  if index.even?
204
233
  group = Decidim::UserGroup.create!(
205
234
  name: Faker::Name.name,
206
- document_number: Faker::Code.isbn,
207
- phone: Faker::PhoneNumber.phone_number,
208
- decidim_organization_id: component.organization.id,
209
- verified_at: Time.current
235
+ nickname: Faker::Twitter.unique.screen_name,
236
+ extended_data: {
237
+ document_number: Faker::Code.isbn,
238
+ phone: Faker::PhoneNumber.phone_number,
239
+ verified_at: Time.current
240
+ },
241
+ decidim_organization_id: component.organization.id
242
+ )
243
+ Decidim::UserGroupMembership.create!(
244
+ user: author,
245
+ role: "creator",
246
+ user_group: group
210
247
  )
211
- author.user_groups << group
212
- author.save!
213
248
  end
214
249
  Decidim::Proposals::ProposalEndorsement.create!(proposal: proposal, author: author, user_group: author.user_groups.first)
215
250
  end
@@ -239,18 +274,20 @@ Decidim.register_component(:proposals) do |component|
239
274
  end
240
275
  author = Decidim::User.where(organization: component.organization).all.sample
241
276
 
242
- draft = Decidim.traceability.create!(
243
- Decidim::Proposals::CollaborativeDraft,
244
- author,
245
- component: component,
246
- category: participatory_space.categories.sample,
247
- scope: Faker::Boolean.boolean(0.5) ? global : scopes.sample,
248
- title: Faker::Lorem.sentence(2),
249
- body: Faker::Lorem.paragraphs(2).join("\n"),
250
- state: state,
251
- published_at: Time.current
252
- )
253
- Decidim::Coauthorship.create(coauthorable: draft, author: author)
277
+ draft = Decidim.traceability.perform_action!("create", Decidim::Proposals::CollaborativeDraft, author) do
278
+ draft = Decidim::Proposals::CollaborativeDraft.new(
279
+ component: component,
280
+ category: participatory_space.categories.sample,
281
+ scope: Faker::Boolean.boolean(0.5) ? global : scopes.sample,
282
+ title: Faker::Lorem.sentence(2),
283
+ body: Faker::Lorem.paragraphs(2).join("\n"),
284
+ state: state,
285
+ published_at: Time.current
286
+ )
287
+ draft.coauthorships.build(author: participatory_space.organization)
288
+ draft.save!
289
+ draft
290
+ end
254
291
 
255
292
  if n == 2
256
293
  author2 = Decidim::User.where(organization: component.organization).all.sample
@@ -113,8 +113,8 @@ module Decidim
113
113
 
114
114
  initializer "decidim_proposals.mentions_listener" do
115
115
  Decidim::Comments::CommentCreation.subscribe do |data|
116
- metadata = data[:metadatas][:proposals]
117
- Decidim::Proposals::NotifyProposalsMentionedJob.perform_later(data[:comment_id], metadata)
116
+ proposals = data.dig(:metadatas, :proposal).try(:linked_proposals)
117
+ Decidim::Proposals::NotifyProposalsMentionedJob.perform_later(data[:comment_id], proposals) if proposals
118
118
  end
119
119
  end
120
120
 
@@ -140,22 +140,42 @@ module Decidim
140
140
  Decidim::Gamification.register_badge(:proposals) do |badge|
141
141
  badge.levels = [1, 5, 10, 30, 60]
142
142
 
143
- badge.reset = lambda { |user|
144
- Decidim::Coauthorship.where(
145
- coauthorable_type: "Decidim::Proposals::Proposal",
146
- author: user
147
- ).count
143
+ badge.valid_for = [:user, :user_group]
144
+
145
+ badge.reset = lambda { |model|
146
+ if model.is_a?(User)
147
+ Decidim::Coauthorship.where(
148
+ coauthorable_type: "Decidim::Proposals::Proposal",
149
+ author: model,
150
+ user_group: nil
151
+ ).count
152
+ elsif model.is_a?(UserGroup)
153
+ Decidim::Coauthorship.where(
154
+ coauthorable_type: "Decidim::Proposals::Proposal",
155
+ user_group: model
156
+ ).count
157
+ end
148
158
  }
149
159
  end
150
160
 
151
161
  Decidim::Gamification.register_badge(:accepted_proposals) do |badge|
152
162
  badge.levels = [1, 5, 15, 30, 50]
153
163
 
154
- badge.reset = lambda { |user|
155
- proposal_ids = Decidim::Coauthorship.where(
156
- coauthorable_type: "Decidim::Proposals::Proposal",
157
- author: user
158
- ).select(:coauthorable_id)
164
+ badge.valid_for = [:user, :user_group]
165
+
166
+ badge.reset = lambda { |model|
167
+ proposal_ids = if model.is_a?(User)
168
+ Decidim::Coauthorship.where(
169
+ coauthorable_type: "Decidim::Proposals::Proposal",
170
+ author: model,
171
+ user_group: nil
172
+ ).select(:coauthorable_id)
173
+ elsif model.is_a?(UserGroup)
174
+ Decidim::Coauthorship.where(
175
+ coauthorable_type: "Decidim::Proposals::Proposal",
176
+ user_group: model
177
+ ).select(:coauthorable_id)
178
+ end
159
179
 
160
180
  Decidim::Proposals::Proposal.where(id: proposal_ids).accepted.count
161
181
  }
@@ -169,6 +189,29 @@ module Decidim
169
189
  }
170
190
  end
171
191
  end
192
+
193
+ initializer "decidim_proposals.register_metrics" do
194
+ Decidim.metrics_registry.register(
195
+ :proposals,
196
+ "Decidim::Proposals::Metrics::ProposalsMetricManage",
197
+ Decidim::MetricRegistry::HIGHLIGHTED,
198
+ 2
199
+ )
200
+
201
+ Decidim.metrics_registry.register(
202
+ :accepted_proposals,
203
+ "Decidim::Proposals::Metrics::AcceptedProposalsMetricManage",
204
+ Decidim::MetricRegistry::NOT_HIGHLIGHTED,
205
+ 3
206
+ )
207
+
208
+ Decidim.metrics_registry.register(
209
+ :votes,
210
+ "Decidim::Proposals::Metrics::VotesMetricManage",
211
+ Decidim::MetricRegistry::HIGHLIGHTED,
212
+ 3
213
+ )
214
+ end
172
215
  end
173
216
  end
174
217
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redcarpet"
4
+
5
+ module Decidim
6
+ module Proposals
7
+ # This class parses a participatory text document in markdown and
8
+ # produces Proposals in the form of sections and articles.
9
+ #
10
+ # This implementation uses Redcarpet Base renderer.
11
+ # Redcarpet::Render::Base performs a callback for every block it finds, what MarkdownToProposals
12
+ # does is to implement callbacks for the blocks which it is interested in performing some actions.
13
+ #
14
+ class MarkdownToProposals < ::Redcarpet::Render::Base
15
+ # Public: Initializes the serializer with a proposal.
16
+ def initialize(component, current_user)
17
+ super()
18
+ @component = component
19
+ @current_user = current_user
20
+ @last_position = 0
21
+ @num_sections = 0
22
+ end
23
+
24
+ def parse(document)
25
+ renderer = self
26
+ parser = ::Redcarpet::Markdown.new(renderer)
27
+ parser.render(document)
28
+ end
29
+
30
+ ##########################################
31
+ # Redcarpet callbacks
32
+ ##########################################
33
+
34
+ # Recarpet callback to process headers.
35
+ # Creates Paricipatory Text Proposals at Section and Subsection levels.
36
+ def header(title, level)
37
+ participatory_text_level = if level > 1
38
+ Decidim::Proposals::ParticipatoryTextSection::LEVELS[:sub_section]
39
+ else
40
+ Decidim::Proposals::ParticipatoryTextSection::LEVELS[:section]
41
+ end
42
+
43
+ create_proposal(title, title, participatory_text_level)
44
+
45
+ @num_sections += 1
46
+ title
47
+ end
48
+
49
+ # Recarpet callback to process paragraphs.
50
+ # Creates Paricipatory Text Proposals at Article level.
51
+ def paragraph(text)
52
+ return if text.blank?
53
+
54
+ create_proposal(
55
+ (@last_position + 1 - @num_sections).to_s,
56
+ text,
57
+ Decidim::Proposals::ParticipatoryTextSection::LEVELS[:article]
58
+ )
59
+
60
+ text
61
+ end
62
+
63
+ # ignore images
64
+ def image(_link, _title, _alt_text)
65
+ ""
66
+ end
67
+
68
+ private
69
+
70
+ def create_proposal(title, body, participatory_text_level)
71
+ attributes = {
72
+ component: @component,
73
+ title: title,
74
+ body: body,
75
+ participatory_text_level: participatory_text_level
76
+ }
77
+
78
+ proposal = Decidim::Proposals::ProposalBuilder.create(
79
+ attributes: attributes,
80
+ author: @component.organization,
81
+ action_user: @current_user
82
+ )
83
+
84
+ @last_position = proposal.position
85
+
86
+ proposal
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # The data store for a Proposal in the Decidim::Proposals component.
6
+ module ParticipatoryTextSection
7
+ extend ActiveSupport::Concern
8
+
9
+ LEVELS = {
10
+ section: "section", sub_section: "sub-section", article: "article"
11
+ }.freeze
12
+
13
+ included do
14
+ # Public: is this section an :article?
15
+ def article?
16
+ participatory_text_level == LEVELS[:article]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -158,6 +158,25 @@ FactoryBot.define do
158
158
  }
159
159
  end
160
160
  end
161
+
162
+ trait :with_minimum_votes_per_user do
163
+ transient do
164
+ minimum_votes_per_user { 3 }
165
+ end
166
+
167
+ settings do
168
+ {
169
+ minimum_votes_per_user: minimum_votes_per_user
170
+ }
171
+ end
172
+ end
173
+ trait :with_participatory_texts_enabled do
174
+ settings do
175
+ {
176
+ participatory_texts_enabled: true
177
+ }
178
+ end
179
+ end
161
180
  end
162
181
 
163
182
  factory :proposal, class: "Decidim::Proposals::Proposal" do
@@ -167,7 +186,7 @@ FactoryBot.define do
167
186
  user_groups { [] }
168
187
  end
169
188
 
170
- title { Faker::Lorem.sentence }
189
+ title { generate(:title) }
171
190
  body { Faker::Lorem.sentences(3).join("\n") }
172
191
  component { create(:proposal_component) }
173
192
  published_at { Time.current }
@@ -178,14 +197,23 @@ FactoryBot.define do
178
197
  users = evaluator.users || [create(:user, organization: proposal.component.participatory_space.organization)]
179
198
  users.each_with_index do |user, idx|
180
199
  user_group = evaluator.user_groups[idx]
181
- Decidim::Coauthorship.create(author: user, user_group: user_group, coauthorable: proposal)
200
+ proposal.coauthorships.build(author: user, user_group: user_group)
182
201
  end
183
202
  end
184
203
  end
185
204
 
205
+ trait :published do
206
+ published_at { Time.current }
207
+ end
208
+
209
+ trait :unpublished do
210
+ published_at { nil }
211
+ end
212
+
186
213
  trait :official do
187
214
  after :build do |proposal|
188
215
  proposal.coauthorships.clear
216
+ proposal.coauthorships.build(author: proposal.organization)
189
217
  end
190
218
  end
191
219
 
@@ -210,7 +238,7 @@ FactoryBot.define do
210
238
 
211
239
  trait :with_answer do
212
240
  state { "accepted" }
213
- answer { Decidim::Faker::Localized.sentence }
241
+ answer { generate_localized_title }
214
242
  answered_at { Time.current }
215
243
  end
216
244
 
@@ -219,8 +247,8 @@ FactoryBot.define do
219
247
  end
220
248
 
221
249
  trait :hidden do
222
- moderation do
223
- create(:moderation, hidden_at: Time.current)
250
+ after :create do |proposal|
251
+ create(:moderation, hidden_at: Time.current, reportable: proposal)
224
252
  end
225
253
  end
226
254
 
@@ -266,7 +294,7 @@ FactoryBot.define do
266
294
  user_groups { [] }
267
295
  end
268
296
 
269
- title { Faker::Lorem.sentence }
297
+ title { generate(:title) }
270
298
  body { Faker::Lorem.sentences(3).join("\n") }
271
299
  component { create(:proposal_component) }
272
300
  address { "#{Faker::Address.street_name}, #{Faker::Address.city}" }
@@ -277,7 +305,7 @@ FactoryBot.define do
277
305
  users = evaluator.users || [create(:user, organization: collaborative_draft.component.participatory_space.organization)]
278
306
  users.each_with_index do |user, idx|
279
307
  user_group = evaluator.user_groups[idx]
280
- Decidim::Coauthorship.create(author: user, user_group: user_group, coauthorable: collaborative_draft)
308
+ collaborative_draft.coauthorships.build(author: user, user_group: user_group)
281
309
  end
282
310
  end
283
311
  end