decidim-proposals 0.9.3 → 0.10.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 +18 -1
  3. data/app/assets/config/admin/decidim_proposals_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +113 -0
  5. data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +56 -0
  6. data/app/commands/decidim/proposals/admin/answer_proposal.rb +11 -5
  7. data/app/commands/decidim/proposals/admin/create_proposal.rb +25 -3
  8. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +13 -8
  9. data/app/commands/decidim/proposals/admin/import_proposals.rb +83 -0
  10. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +68 -0
  11. data/app/commands/decidim/proposals/create_proposal.rb +0 -12
  12. data/app/commands/decidim/proposals/endorse_proposal.rb +56 -0
  13. data/app/commands/decidim/proposals/publish_proposal.rb +60 -0
  14. data/app/commands/decidim/proposals/unendorse_proposal.rb +40 -0
  15. data/app/commands/decidim/proposals/update_proposal.rb +3 -3
  16. data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
  17. data/app/commands/decidim/proposals/withdraw_proposal.rb +1 -1
  18. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  19. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +2 -2
  20. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +50 -1
  21. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +35 -0
  22. data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +56 -0
  23. data/app/controllers/decidim/proposals/proposals_controller.rb +82 -9
  24. data/app/events/decidim/proposals/admin/update_proposal_category_event.rb +11 -0
  25. data/app/events/decidim/proposals/creation_enabled_event.rb +8 -0
  26. data/app/events/decidim/proposals/endorsing_enabled_event.rb +8 -0
  27. data/app/events/decidim/proposals/proposal_endorsed_event.rb +29 -0
  28. data/app/events/decidim/proposals/publish_proposal_event.rb +21 -0
  29. data/app/events/decidim/proposals/voting_enabled_event.rb +8 -0
  30. data/app/forms/decidim/proposals/admin/proposal_form.rb +9 -2
  31. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +60 -0
  32. data/app/forms/decidim/proposals/proposal_form.rb +16 -5
  33. data/app/helpers/decidim/proposals/application_helper.rb +1 -0
  34. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +117 -0
  35. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +13 -6
  36. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +105 -0
  37. data/app/jobs/decidim/proposals/settings_change_job.rb +48 -0
  38. data/app/models/decidim/proposals/abilities/current_user_ability.rb +30 -8
  39. data/app/models/decidim/proposals/proposal.rb +38 -38
  40. data/app/models/decidim/proposals/proposal_endorsement.rb +31 -0
  41. data/app/models/decidim/proposals/proposal_note.rb +7 -0
  42. data/app/presenters/decidim/proposals/admin_log/proposal_note_presenter.rb +39 -0
  43. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +47 -0
  44. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_state_presenter.rb +16 -0
  45. data/app/queries/decidim/proposals/similar_proposals.rb +53 -0
  46. data/app/types/decidim/proposals/proposal_type.rb +34 -0
  47. data/app/types/decidim/proposals/proposals_type.rb +34 -0
  48. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +8 -0
  49. data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +27 -0
  50. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +10 -0
  51. data/app/views/decidim/participatory_spaces/_proposal.html.erb +27 -0
  52. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +15 -0
  53. data/app/views/decidim/proposals/admin/proposals/_js-callout.html.erb +6 -0
  54. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +63 -0
  55. data/app/views/decidim/proposals/admin/proposals/index.html.erb +12 -73
  56. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +25 -0
  57. data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +28 -0
  58. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +4 -0
  59. data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +12 -0
  60. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +9 -0
  61. data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +11 -0
  62. data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +13 -0
  63. data/app/views/decidim/proposals/proposals/_endorsement_xxs.html.erb +9 -0
  64. data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +22 -0
  65. data/app/views/decidim/proposals/proposals/_endorsements_count.html.erb +5 -0
  66. data/app/views/decidim/proposals/proposals/_endorsements_listing.html.erb +34 -0
  67. data/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -2
  68. data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +36 -0
  69. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +21 -0
  70. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +8 -8
  71. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +23 -6
  72. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +7 -3
  73. data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +16 -0
  74. data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +31 -0
  75. data/app/views/decidim/proposals/proposals/compare.html.erb +19 -0
  76. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +55 -0
  77. data/app/views/decidim/proposals/proposals/new.html.erb +7 -20
  78. data/app/views/decidim/proposals/proposals/preview.html.erb +18 -0
  79. data/app/views/decidim/proposals/proposals/show.html.erb +13 -4
  80. data/config/locales/ca.yml +156 -15
  81. data/config/locales/en.yml +156 -15
  82. data/config/locales/es.yml +157 -16
  83. data/config/locales/eu.yml +151 -7
  84. data/config/locales/fi.yml +151 -7
  85. data/config/locales/fr.yml +153 -9
  86. data/config/locales/gl.yml +151 -7
  87. data/config/locales/it.yml +151 -7
  88. data/config/locales/nl.yml +151 -7
  89. data/config/locales/pl.yml +148 -22
  90. data/config/locales/pt-BR.yml +151 -7
  91. data/config/locales/pt.yml +151 -7
  92. data/config/locales/ru.yml +0 -9
  93. data/config/locales/sv.yml +151 -7
  94. data/config/locales/uk.yml +87 -13
  95. data/db/migrate/20170307085300_migrate_proposal_reports_data_to_reports.rb +1 -1
  96. data/db/migrate/20171201115434_create_proposal_endorsements.rb +16 -0
  97. data/db/migrate/20171201122623_add_counter_cache_endorsements_to_proposals.rb +8 -0
  98. data/db/migrate/20171212102250_enable_pg_extensions.rb +7 -0
  99. data/db/migrate/20171220084719_add_published_at_to_proposals.rb +14 -0
  100. data/lib/decidim/proposals.rb +15 -0
  101. data/lib/decidim/proposals/admin_engine.rb +8 -0
  102. data/lib/decidim/proposals/commentable_proposal.rb +39 -0
  103. data/lib/decidim/proposals/engine.rb +69 -1
  104. data/lib/decidim/proposals/feature.rb +51 -6
  105. data/lib/decidim/proposals/test/factories.rb +78 -2
  106. data/lib/decidim/proposals/version.rb +1 -1
  107. metadata +76 -20
  108. data/app/events/decidim/proposals/create_proposal_event.rb +0 -9
@@ -14,7 +14,7 @@ class MigrateProposalReportsDataToReports < ActiveRecord::Migration[5.0]
14
14
  user: proposal_report.user,
15
15
  reason: proposal_report.reason,
16
16
  details: proposal_report.details)
17
- moderation.update_attributes!(report_count: moderation.report_count + 1)
17
+ moderation.update!(report_count: moderation.report_count + 1)
18
18
  end
19
19
 
20
20
  drop_table :decidim_proposals_proposal_reports
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateProposalEndorsements < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :decidim_proposals_proposal_endorsements do |t|
6
+ t.references :decidim_proposal, null: false, index: { name: "decidim_proposals_proposal_endorsement_proposal" }
7
+ t.references :decidim_author, null: false, index: { name: "decidim_proposals_proposal_endorsement_author" }
8
+ t.references :decidim_user_group, null: true, index: { name: "decidim_proposals_proposal_endorsement_user_group" }
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :decidim_proposals_proposal_endorsements, "decidim_proposal_id, decidim_author_id, (coalesce(decidim_user_group_id,-1))", unique: true, name:
14
+ "decidim_proposals_proposal_endorsmt_proposal_auth_ugroup_uniq"
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCounterCacheEndorsementsToProposals < ActiveRecord::Migration[5.1]
4
+ def change
5
+ add_column :decidim_proposals_proposals, :proposal_endorsements_count, :integer, null: false, default: 0
6
+ add_index :decidim_proposals_proposals, :proposal_endorsements_count, name: "idx_decidim_proposals_proposals_on_proposal_endorsemnts_count"
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class EnablePgExtensions < ActiveRecord::Migration[5.1]
4
+ def change
5
+ enable_extension "pg_trgm"
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddPublishedAtToProposals < ActiveRecord::Migration[5.1]
4
+ def up
5
+ add_column :decidim_proposals_proposals, :published_at, :datetime, index: true
6
+ # rubocop:disable Rails/SkipsModelValidations
7
+ Decidim::Proposals::Proposal.update_all("published_at = updated_at")
8
+ # rubocop:enable Rails/SkipsModelValidations
9
+ end
10
+
11
+ def down
12
+ remove_column :decidim_proposals_proposals, :published_at
13
+ end
14
+ end
@@ -10,5 +10,20 @@ module Decidim
10
10
  # allows users to create proposals in a participatory process.
11
11
  module Proposals
12
12
  autoload :ProposalSerializer, "decidim/proposals/proposal_serializer"
13
+ autoload :CommentableProposal, "decidim/proposals/commentable_proposal"
14
+
15
+ include ActiveSupport::Configurable
16
+
17
+ # Public Setting that defines the similarity minimum value to consider two
18
+ # proposals similar. Defaults to 0.25.
19
+ config_accessor :similarity_threshold do
20
+ 0.25
21
+ end
22
+
23
+ # Public Setting that defines how many similar proposals will be shown.
24
+ # Defaults to 10.
25
+ config_accessor :similarity_limit do
26
+ 10
27
+ end
13
28
  end
14
29
  end
@@ -10,6 +10,10 @@ module Decidim
10
10
 
11
11
  routes do
12
12
  resources :proposals, only: [:index, :new, :create] do
13
+ post :update_category, on: :collection
14
+ collection do
15
+ resource :proposals_import, only: [:new, :create]
16
+ end
13
17
  resources :proposal_answers, only: [:edit, :update]
14
18
  resources :proposal_notes, only: [:index, :create]
15
19
  end
@@ -17,6 +21,10 @@ module Decidim
17
21
  root to: "proposals#index"
18
22
  end
19
23
 
24
+ initializer "decidim_proposals.admin_assets" do |app|
25
+ app.config.assets.precompile += %w(admin/decidim_proposals_manifest.js)
26
+ end
27
+
20
28
  initializer "decidim_proposals.inject_abilities_to_user" do |_app|
21
29
  Decidim.configure do |config|
22
30
  config.admin_abilities += [
@@ -0,0 +1,39 @@
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 CommentableProposal
7
+ extend ActiveSupport::Concern
8
+ include Decidim::Comments::Commentable
9
+
10
+ included do
11
+ # Public: Overrides the `commentable?` Commentable concern method.
12
+ def commentable?
13
+ feature.settings.comments_enabled?
14
+ end
15
+
16
+ # Public: Overrides the `accepts_new_comments?` Commentable concern method.
17
+ def accepts_new_comments?
18
+ commentable? && !feature.current_settings.comments_blocked
19
+ end
20
+
21
+ # Public: Overrides the `comments_have_alignment?` Commentable concern method.
22
+ def comments_have_alignment?
23
+ true
24
+ end
25
+
26
+ # Public: Overrides the `comments_have_votes?` Commentable concern method.
27
+ def comments_have_votes?
28
+ true
29
+ end
30
+
31
+ # Public: Override Commentable concern method `users_to_notify_on_comment_created`
32
+ def users_to_notify_on_comment_created
33
+ return (followers | feature.participatory_space.admins).uniq if official?
34
+ followers
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -14,7 +14,15 @@ module Decidim
14
14
 
15
15
  routes do
16
16
  resources :proposals, except: [:destroy] do
17
+ resource :proposal_endorsement, only: [:create, :destroy] do
18
+ get :identities, on: :collection
19
+ end
17
20
  member do
21
+ get :compare
22
+ get :edit_draft
23
+ patch :update_draft
24
+ get :preview
25
+ post :publish
18
26
  put :withdraw
19
27
  end
20
28
  resource :proposal_vote, only: [:create, :destroy]
@@ -24,7 +32,9 @@ module Decidim
24
32
  end
25
33
 
26
34
  initializer "decidim_proposals.assets" do |app|
27
- app.config.assets.precompile += %w(decidim_proposals_manifest.js decidim_proposals_manifest.css)
35
+ app.config.assets.precompile += %w(decidim_proposals_manifest.js
36
+ decidim_proposals_manifest.css
37
+ decidim/proposals/identity_selector_dialog.js)
28
38
  end
29
39
 
30
40
  initializer "decidim_proposals.inject_abilities_to_user" do |_app|
@@ -32,6 +42,64 @@ module Decidim
32
42
  config.abilities += ["Decidim::Proposals::Abilities::CurrentUserAbility"]
33
43
  end
34
44
  end
45
+
46
+ initializer "decidim_proposals.view_hooks" do
47
+ Decidim.view_hooks.register(:participatory_space_highlighted_elements, priority: Decidim::ViewHooks::MEDIUM_PRIORITY) do |view_context|
48
+ published_features = Decidim::Feature.where(participatory_space: view_context.current_participatory_space).published
49
+ proposals = Decidim::Proposals::Proposal.where(feature: published_features).order_randomly(rand * 2 - 1).limit(4)
50
+
51
+ next unless proposals.any?
52
+
53
+ view_context.extend Decidim::Proposals::ApplicationHelper
54
+ view_context.render(
55
+ partial: "decidim/participatory_spaces/highlighted_proposals",
56
+ locals: {
57
+ proposals: proposals
58
+ }
59
+ )
60
+ end
61
+
62
+ if defined? Decidim::ParticipatoryProcesses
63
+ Decidim::ParticipatoryProcesses.view_hooks.register(:process_group_highlighted_elements, priority: Decidim::ViewHooks::MEDIUM_PRIORITY) do |view_context|
64
+ published_features = Decidim::Feature.where(participatory_space: view_context.participatory_processes).published
65
+ proposals = Decidim::Proposals::Proposal.where(feature: published_features).order_randomly(rand * 2 - 1).limit(3)
66
+
67
+ next unless proposals.any?
68
+
69
+ view_context.extend Decidim::ResourceReferenceHelper
70
+ view_context.extend Decidim::Proposals::ApplicationHelper
71
+ view_context.render(
72
+ partial: "decidim/participatory_processes/participatory_process_groups/highlighted_proposals",
73
+ locals: {
74
+ proposals: proposals
75
+ }
76
+ )
77
+ end
78
+ end
79
+ end
80
+
81
+ initializer "decidim_changes" do
82
+ Decidim::SettingsChange.subscribe "surveys" do |changes|
83
+ Decidim::Proposals::SettingsChangeJob.perform_later(
84
+ changes[:feature_id],
85
+ changes[:previous_settings],
86
+ changes[:current_settings]
87
+ )
88
+ end
89
+ end
90
+
91
+ # Subscribes to ActiveSupport::Notifications that may affect a Proposal.
92
+ initializer "decidim_proposals.subscribe_to_events" do
93
+ # when a proposal is linked from a result
94
+ event_name = "decidim.resourceable.included_proposals.created"
95
+ ActiveSupport::Notifications.subscribe event_name do |_name, _started, _finished, _unique_id, data|
96
+ payload = data[:this]
97
+ if payload[:from_type] == Decidim::Accountability::Result.name && payload[:to_type] == Proposal.name
98
+ proposal = Proposal.find(payload[:to_id])
99
+ proposal.update(state: "accepted")
100
+ end
101
+ end
102
+ end
35
103
  end
36
104
  end
37
105
  end
@@ -11,13 +11,17 @@ Decidim.register_feature(:proposals) do |feature|
11
11
  raise "Can't destroy this feature when there are proposals" if Decidim::Proposals::Proposal.where(feature: instance).any?
12
12
  end
13
13
 
14
- feature.actions = %w(vote create withdraw)
14
+ feature.actions = %w(endorse vote create withdraw)
15
+
16
+ feature.query_type = "Decidim::Proposals::ProposalsType"
15
17
 
16
18
  feature.settings(:global) do |settings|
17
19
  settings.attribute :vote_limit, type: :integer, default: 0
18
20
  settings.attribute :proposal_limit, type: :integer, default: 0
21
+ settings.attribute :proposal_length, type: :integer, default: 500
19
22
  settings.attribute :proposal_edit_before_minutes, type: :integer, default: 5
20
- settings.attribute :maximum_votes_per_proposal, type: :integer, default: 0
23
+ settings.attribute :threshold_per_proposal, type: :integer, default: 0
24
+ settings.attribute :can_accumulate_supports_beyond_threshold, type: :boolean, default: false
21
25
  settings.attribute :proposal_answering_enabled, type: :boolean, default: true
22
26
  settings.attribute :official_proposals_enabled, type: :boolean, default: true
23
27
  settings.attribute :comments_enabled, type: :boolean, default: true
@@ -25,9 +29,14 @@ Decidim.register_feature(:proposals) do |feature|
25
29
  settings.attribute :attachments_allowed, type: :boolean, default: false
26
30
  settings.attribute :announcement, type: :text, translated: true, editor: true
27
31
  settings.attribute :new_proposal_help_text, type: :text, translated: true, editor: true
32
+ settings.attribute :proposal_wizard_step_1_help_text, type: :text, translated: true, editor: true
33
+ settings.attribute :proposal_wizard_step_2_help_text, type: :text, translated: true, editor: true
34
+ settings.attribute :proposal_wizard_step_3_help_text, type: :text, translated: true, editor: true
28
35
  end
29
36
 
30
37
  feature.settings(:step) do |settings|
38
+ settings.attribute :endorsements_enabled, type: :boolean, default: true
39
+ settings.attribute :endorsements_blocked, type: :boolean
31
40
  settings.attribute :votes_enabled, type: :boolean
32
41
  settings.attribute :votes_blocked, type: :boolean
33
42
  settings.attribute :votes_hidden, type: :boolean, default: false
@@ -43,7 +52,7 @@ Decidim.register_feature(:proposals) do |feature|
43
52
  end
44
53
 
45
54
  feature.register_stat :proposals_count, primary: true, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |features, start_at, end_at|
46
- Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).not_hidden.count
55
+ Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).published.not_hidden.count
47
56
  end
48
57
 
49
58
  feature.register_stat :proposals_accepted, primary: true, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |features, start_at, end_at|
@@ -51,12 +60,17 @@ Decidim.register_feature(:proposals) do |feature|
51
60
  end
52
61
 
53
62
  feature.register_stat :votes_count, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |features, start_at, end_at|
54
- proposals = Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).not_hidden
63
+ proposals = Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).published.not_hidden
55
64
  Decidim::Proposals::ProposalVote.where(proposal: proposals).count
56
65
  end
57
66
 
58
- feature.register_stat :comments_count, tag: :comments do |features, start_at, end_at|
67
+ feature.register_stat :endorsements_count, priority: Decidim::StatsRegistry::MEDIUM_PRIORITY do |features, start_at, end_at|
59
68
  proposals = Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).not_hidden
69
+ Decidim::Proposals::ProposalEndorsement.where(proposal: proposals).count
70
+ end
71
+
72
+ feature.register_stat :comments_count, tag: :comments do |features, start_at, end_at|
73
+ proposals = Decidim::Proposals::FilteredProposals.for(features, start_at, end_at).published.not_hidden
60
74
  Decidim::Comments::Comment.where(root_commentable: proposals).count
61
75
  end
62
76
 
@@ -129,7 +143,8 @@ Decidim.register_feature(:proposals) do |feature|
129
143
  user_group: user_group,
130
144
  state: state,
131
145
  answer: answer,
132
- answered_at: Time.current
146
+ answered_at: Time.current,
147
+ published_at: Time.current
133
148
  )
134
149
 
135
150
  (n % 3).times do |m|
@@ -152,6 +167,36 @@ Decidim.register_feature(:proposals) do |feature|
152
167
  Decidim::Proposals::ProposalVote.create!(proposal: proposal, author: author) unless proposal.answered? && proposal.rejected?
153
168
  end
154
169
 
170
+ unless proposal.answered? && proposal.rejected?
171
+ (n * 2).times do |index|
172
+ email = "endorsement-author-#{participatory_space.underscored_name}-#{participatory_space.id}-#{n}-endr#{index}@example.org"
173
+ name = "#{Faker::Name.name} #{participatory_space.id} #{n} endr#{index}"
174
+
175
+ author = Decidim::User.find_or_initialize_by(email: email)
176
+ author.update!(
177
+ password: "password1234",
178
+ password_confirmation: "password1234",
179
+ name: name,
180
+ nickname: Faker::Twitter.unique.screen_name,
181
+ organization: feature.organization,
182
+ tos_agreement: "1",
183
+ confirmed_at: Time.current
184
+ )
185
+ if index.even?
186
+ group = Decidim::UserGroup.create!(
187
+ name: Faker::Name.name,
188
+ document_number: Faker::Code.isbn,
189
+ phone: Faker::PhoneNumber.phone_number,
190
+ decidim_organization_id: feature.organization.id,
191
+ verified_at: Time.current
192
+ )
193
+ author.user_groups << group
194
+ author.save!
195
+ end
196
+ Decidim::Proposals::ProposalEndorsement.create!(proposal: proposal, author: author, user_group: author.user_groups.first)
197
+ end
198
+ end
199
+
155
200
  (n % 3).times do
156
201
  author_admin = Decidim::User.where(organization: feature.organization, admin: true).all.sample
157
202
 
@@ -9,6 +9,22 @@ FactoryBot.define do
9
9
  manifest_name :proposals
10
10
  participatory_space { create(:participatory_process, :with_steps, organization: organization) }
11
11
 
12
+ trait :with_endorsements_enabled do
13
+ step_settings do
14
+ {
15
+ participatory_space.active_step.id => { endorsements_enabled: true }
16
+ }
17
+ end
18
+ end
19
+
20
+ trait :with_endorsements_disabled do
21
+ step_settings do
22
+ {
23
+ participatory_space.active_step.id => { endorsements_enabled: false }
24
+ }
25
+ end
26
+ end
27
+
12
28
  trait :with_votes_enabled do
13
29
  step_settings do
14
30
  {
@@ -25,6 +41,14 @@ FactoryBot.define do
25
41
  end
26
42
  end
27
43
 
44
+ trait :with_votes_hidden do
45
+ step_settings do
46
+ {
47
+ participatory_space.active_step.id => { votes_hidden: true }
48
+ }
49
+ end
50
+ end
51
+
28
52
  trait :with_vote_limit do
29
53
  transient do
30
54
  vote_limit 10
@@ -49,6 +73,17 @@ FactoryBot.define do
49
73
  end
50
74
  end
51
75
 
76
+ trait :with_endorsements_blocked do
77
+ step_settings do
78
+ {
79
+ participatory_space.active_step.id => {
80
+ endorsements_enabled: true,
81
+ endorsements_blocked: true
82
+ }
83
+ }
84
+ end
85
+ end
86
+
52
87
  trait :with_votes_blocked do
53
88
  step_settings do
54
89
  {
@@ -84,10 +119,18 @@ FactoryBot.define do
84
119
  end
85
120
  end
86
121
 
87
- trait :with_maximum_votes_per_proposal do
122
+ trait :with_threshold_per_proposal do
123
+ settings do
124
+ {
125
+ threshold_per_proposal: 1
126
+ }
127
+ end
128
+ end
129
+
130
+ trait :with_can_accumulate_supports_beyond_threshold do
88
131
  settings do
89
132
  {
90
- maximum_votes_per_proposal: 1
133
+ can_accumulate_supports_beyond_threshold: true
91
134
  }
92
135
  end
93
136
  end
@@ -97,6 +140,9 @@ FactoryBot.define do
97
140
  title { Faker::Lorem.sentence }
98
141
  body { Faker::Lorem.sentences(3).join("\n") }
99
142
  feature { create(:proposal_feature) }
143
+ published_at { Time.current }
144
+ address { "#{Faker::Address.street_name}, #{Faker::Address.city}" }
145
+
100
146
  author do
101
147
  create(:user, organization: feature.organization) if feature
102
148
  end
@@ -128,6 +174,22 @@ FactoryBot.define do
128
174
  answer { Decidim::Faker::Localized.sentence }
129
175
  answered_at { Time.current }
130
176
  end
177
+
178
+ trait :draft do
179
+ published_at nil
180
+ end
181
+
182
+ trait :with_votes do
183
+ after :create do |proposal|
184
+ create_list(:proposal_vote, 5, proposal: proposal)
185
+ end
186
+ end
187
+
188
+ trait :with_endorsements do
189
+ after :create do |proposal|
190
+ create_list(:proposal_endorsement, 5, proposal: proposal)
191
+ end
192
+ end
131
193
  end
132
194
 
133
195
  factory :proposal_vote, class: "Decidim::Proposals::ProposalVote" do
@@ -135,6 +197,20 @@ FactoryBot.define do
135
197
  author { build(:user, organization: proposal.organization) }
136
198
  end
137
199
 
200
+ factory :proposal_endorsement, class: "Decidim::Proposals::ProposalEndorsement" do
201
+ proposal { build(:proposal) }
202
+ author { build(:user, organization: proposal.organization) }
203
+ end
204
+
205
+ factory :user_group_proposal_endorsement, class: "Decidim::Proposals::ProposalEndorsement" do
206
+ proposal { build(:proposal) }
207
+ author { build(:user, organization: proposal.organization) }
208
+ user_group { create(:user_group) }
209
+ after(:create) do |support|
210
+ create(:user_group_membership, user: support.author, user_group: Decidim::UserGroup.find(support.decidim_user_group_id))
211
+ end
212
+ end
213
+
138
214
  factory :proposal_note, class: "Decidim::Proposals::ProposalNote" do
139
215
  body { Faker::Lorem.sentences(3).join("\n") }
140
216
  proposal { build(:proposal) }