decidim-elections 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +31 -0
  3. data/Rakefile +3 -0
  4. data/app/assets/config/decidim_elections_manifest.js +0 -0
  5. data/app/assets/images/decidim/elections/icon.svg +1 -0
  6. data/app/commands/decidim/elections/admin/create_answer.rb +71 -0
  7. data/app/commands/decidim/elections/admin/create_election.rb +48 -0
  8. data/app/commands/decidim/elections/admin/create_question.rb +52 -0
  9. data/app/commands/decidim/elections/admin/destroy_answer.rb +50 -0
  10. data/app/commands/decidim/elections/admin/destroy_election.rb +46 -0
  11. data/app/commands/decidim/elections/admin/destroy_question.rb +46 -0
  12. data/app/commands/decidim/elections/admin/update_answer.rb +73 -0
  13. data/app/commands/decidim/elections/admin/update_election.rb +48 -0
  14. data/app/commands/decidim/elections/admin/update_question.rb +52 -0
  15. data/app/controllers/decidim/elections/admin/answers_controller.rb +92 -0
  16. data/app/controllers/decidim/elections/admin/application_controller.rb +15 -0
  17. data/app/controllers/decidim/elections/admin/elections_controller.rb +82 -0
  18. data/app/controllers/decidim/elections/admin/questions_controller.rb +86 -0
  19. data/app/controllers/decidim/elections/application_controller.rb +13 -0
  20. data/app/controllers/decidim/elections/elections_controller.rb +9 -0
  21. data/app/forms/decidim/elections/admin/answer_form.rb +53 -0
  22. data/app/forms/decidim/elections/admin/election_form.rb +24 -0
  23. data/app/forms/decidim/elections/admin/question_form.rb +26 -0
  24. data/app/helpers/decidim/elections/application_helper.rb +10 -0
  25. data/app/models/decidim/elections/answer.rb +26 -0
  26. data/app/models/decidim/elections/application_record.rb +10 -0
  27. data/app/models/decidim/elections/election.rb +22 -0
  28. data/app/models/decidim/elections/question.rb +20 -0
  29. data/app/permissions/decidim/elections/admin/permissions.rb +42 -0
  30. data/app/permissions/decidim/elections/permissions.rb +16 -0
  31. data/app/types/decidim/elections/election_answer_type.rb +24 -0
  32. data/app/types/decidim/elections/election_question_type.rb +25 -0
  33. data/app/types/decidim/elections/election_type.rb +26 -0
  34. data/app/types/decidim/elections/elections_type.rb +32 -0
  35. data/app/views/decidim/elections/admin/answers/_form.html.erb +25 -0
  36. data/app/views/decidim/elections/admin/answers/edit.html.erb +7 -0
  37. data/app/views/decidim/elections/admin/answers/index.html.erb +46 -0
  38. data/app/views/decidim/elections/admin/answers/new.html.erb +7 -0
  39. data/app/views/decidim/elections/admin/answers/proposals_picker.html.erb +1 -0
  40. data/app/views/decidim/elections/admin/elections/_form.html.erb +28 -0
  41. data/app/views/decidim/elections/admin/elections/edit.html.erb +7 -0
  42. data/app/views/decidim/elections/admin/elections/index.html.erb +54 -0
  43. data/app/views/decidim/elections/admin/elections/new.html.erb +7 -0
  44. data/app/views/decidim/elections/admin/questions/_form.html.erb +27 -0
  45. data/app/views/decidim/elections/admin/questions/edit.html.erb +7 -0
  46. data/app/views/decidim/elections/admin/questions/index.html.erb +53 -0
  47. data/app/views/decidim/elections/admin/questions/new.html.erb +7 -0
  48. data/app/views/decidim/elections/elections/index.html.erb +1 -0
  49. data/app/views/decidim/elections/elections/show.html.erb +0 -0
  50. data/config/i18n-tasks.yml +10 -0
  51. data/config/locales/ar.yml +1 -0
  52. data/config/locales/bg-BG.yml +7 -0
  53. data/config/locales/ca.yml +132 -0
  54. data/config/locales/cs.yml +138 -0
  55. data/config/locales/da-DK.yml +1 -0
  56. data/config/locales/de.yml +132 -0
  57. data/config/locales/el.yml +132 -0
  58. data/config/locales/en.yml +133 -0
  59. data/config/locales/eo-UY.yml +1 -0
  60. data/config/locales/es-MX.yml +132 -0
  61. data/config/locales/es-PY.yml +132 -0
  62. data/config/locales/es.yml +132 -0
  63. data/config/locales/et-EE.yml +1 -0
  64. data/config/locales/eu.yml +1 -0
  65. data/config/locales/fi-plain.yml +132 -0
  66. data/config/locales/fi.yml +132 -0
  67. data/config/locales/fr-CA.yml +132 -0
  68. data/config/locales/fr.yml +132 -0
  69. data/config/locales/ga-IE.yml +1 -0
  70. data/config/locales/gl.yml +1 -0
  71. data/config/locales/hr-HR.yml +1 -0
  72. data/config/locales/hu.yml +1 -0
  73. data/config/locales/id-ID.yml +1 -0
  74. data/config/locales/is-IS.yml +1 -0
  75. data/config/locales/it.yml +132 -0
  76. data/config/locales/ja-JP.yml +129 -0
  77. data/config/locales/lt-LT.yml +1 -0
  78. data/config/locales/lv-LV.yml +135 -0
  79. data/config/locales/mt-MT.yml +1 -0
  80. data/config/locales/nl.yml +132 -0
  81. data/config/locales/no.yml +9 -0
  82. data/config/locales/pl.yml +138 -0
  83. data/config/locales/pt-BR.yml +1 -0
  84. data/config/locales/pt.yml +132 -0
  85. data/config/locales/ro-RO.yml +135 -0
  86. data/config/locales/ru.yml +1 -0
  87. data/config/locales/sk.yml +1 -0
  88. data/config/locales/sl.yml +5 -0
  89. data/config/locales/sr-CS.yml +1 -0
  90. data/config/locales/sv.yml +132 -0
  91. data/config/locales/tr-TR.yml +1 -0
  92. data/config/locales/uk.yml +1 -0
  93. data/db/migrate/20200430083618_create_decidim_elections_elections.rb +15 -0
  94. data/db/migrate/20200518082327_create_decidim_elections_questions.rb +14 -0
  95. data/db/migrate/20200518084144_create_decidim_elections_answers.rb +12 -0
  96. data/lib/decidim/elections.rb +13 -0
  97. data/lib/decidim/elections/admin.rb +10 -0
  98. data/lib/decidim/elections/admin_engine.rb +29 -0
  99. data/lib/decidim/elections/component.rb +123 -0
  100. data/lib/decidim/elections/engine.rb +23 -0
  101. data/lib/decidim/elections/seeds/city.jpeg +0 -0
  102. data/lib/decidim/elections/test/factories.rb +52 -0
  103. data/lib/decidim/elections/version.rb +10 -0
  104. metadata +201 -0
@@ -0,0 +1 @@
1
+ ru:
@@ -0,0 +1 @@
1
+ sk:
@@ -0,0 +1,5 @@
1
+ sl:
2
+ activemodel:
3
+ attributes:
4
+ answer:
5
+ description: Opis
@@ -0,0 +1 @@
1
+ sr:
@@ -0,0 +1,132 @@
1
+ sv:
2
+ activemodel:
3
+ attributes:
4
+ answer:
5
+ description: Beskrivning
6
+ image: Bild
7
+ proposals: Relaterade förslag
8
+ title: Titel
9
+ election:
10
+ description: Beskrivning
11
+ end_time: Omröstningen slutar vid
12
+ start_time: Röstningsstart vid
13
+ subtitle: Undertext
14
+ title: Titel
15
+ question:
16
+ description: Beskrivning
17
+ max_selections: Maximalt antal val
18
+ title: Titel
19
+ errors:
20
+ models:
21
+ answer:
22
+ attributes:
23
+ attachment:
24
+ needs_to_be_reattached: Måste återknytas
25
+ activerecord:
26
+ models:
27
+ decidim/elections/answer:
28
+ one: Svar
29
+ other: Svar
30
+ decidim/elections/election:
31
+ one: Val
32
+ other: Val
33
+ decidim/elections/question:
34
+ one: Fråga
35
+ other: Frågor
36
+ decidim:
37
+ components:
38
+ elections:
39
+ name: Val
40
+ settings:
41
+ global:
42
+ announcement: Meddelande
43
+ step:
44
+ announcement: Meddelande
45
+ elections:
46
+ actions:
47
+ confirm_destroy: Är du säker?
48
+ destroy: Förstör
49
+ edit: Redigera
50
+ new: Ny %{name}
51
+ preview: Förhandsgranska
52
+ title: Åtgärder
53
+ admin:
54
+ answers:
55
+ create:
56
+ invalid: Det gick inte att skapa svaret
57
+ success: Svaret har skapats
58
+ destroy:
59
+ invalid: Det gick inte att ta bort svaret
60
+ success: Svaret har tagits bort
61
+ edit:
62
+ title: Redigera svar
63
+ update: Uppdatera svar
64
+ index:
65
+ title: Svar
66
+ new:
67
+ create: Skapa svar
68
+ title: Nytt svar
69
+ update:
70
+ invalid: Det gick inte att uppdatera svaret
71
+ success: Svaret har uppdaterats
72
+ elections:
73
+ create:
74
+ invalid: Det gick inte att skapa detta val
75
+ success: Val har skapats
76
+ destroy:
77
+ invalid: Det gick inte att ta bort valet
78
+ success: Val har tagits bort
79
+ edit:
80
+ title: Redigera val
81
+ update: Uppdatera val
82
+ index:
83
+ title: Val
84
+ new:
85
+ create: Skapa val
86
+ title: Nytt val
87
+ update:
88
+ invalid: Det gick inte att uppdatera valet
89
+ success: Val har uppdaterats
90
+ models:
91
+ answer:
92
+ name: Svar
93
+ election:
94
+ name: Val
95
+ question:
96
+ name: Fråga
97
+ questions:
98
+ create:
99
+ invalid: Det gick inte att skapa denna fråga
100
+ success: Frågan har skapats
101
+ destroy:
102
+ invalid: Det gick inte att ta bort denna fråga
103
+ success: Frågan har tagits bort
104
+ edit:
105
+ title: Redigera fråga
106
+ update: Uppdatera fråga
107
+ index:
108
+ title: Frågor
109
+ new:
110
+ create: Skapa fråga
111
+ title: Ny fråga
112
+ update:
113
+ invalid: Det gick inte att uppdatera denna fråga
114
+ success: Frågan har uppdaterats
115
+ models:
116
+ answer:
117
+ fields:
118
+ proposals: Förslag
119
+ title: Titel
120
+ election:
121
+ fields:
122
+ end_time: Avsluta vid
123
+ start_time: Börjar vid
124
+ title: Titel
125
+ question:
126
+ fields:
127
+ answers: Svar
128
+ max_selections: Max. val
129
+ title: Titel
130
+ participatory_processes:
131
+ statistics:
132
+ elections_count: Val
@@ -0,0 +1 @@
1
+ tr:
@@ -0,0 +1 @@
1
+ uk:
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDecidimElectionsElections < ActiveRecord::Migration[5.2]
4
+ def change
5
+ create_table :decidim_elections_elections do |t|
6
+ t.jsonb :title
7
+ t.jsonb :subtitle
8
+ t.jsonb :description
9
+ t.datetime :start_time
10
+ t.datetime :end_time
11
+ t.references :decidim_component, index: true
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDecidimElectionsQuestions < ActiveRecord::Migration[5.2]
4
+ def change
5
+ create_table :decidim_elections_questions do |t|
6
+ t.references :decidim_elections_election, null: false, index: { name: "decidim_elections_elections_questions" }
7
+ t.jsonb :title, null: false
8
+ t.jsonb :description
9
+ t.integer :max_selections, null: false, default: 1
10
+ t.integer :weight, null: false, default: 0
11
+ t.boolean :random_answers_order, null: false, default: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDecidimElectionsAnswers < ActiveRecord::Migration[5.2]
4
+ def change
5
+ create_table :decidim_elections_answers do |t|
6
+ t.references :decidim_elections_question, null: false, index: { name: "decidim_elections_questions_answers" }
7
+ t.jsonb :title, null: false
8
+ t.jsonb :description
9
+ t.integer :weight, null: false, default: 0
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/elections/admin"
4
+ require "decidim/elections/engine"
5
+ require "decidim/elections/admin_engine"
6
+ require "decidim/elections/component"
7
+
8
+ module Decidim
9
+ # This namespace holds the logic of the `Elections` component. This component
10
+ # allows users to create elections in a participatory space.
11
+ module Elections
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Elections
5
+ # This module contains all the domain logic associated to Decidim's Elections
6
+ # component admin panel.
7
+ module Admin
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Elections
5
+ # This is the engine that runs on the public interface of `Elections`.
6
+ class AdminEngine < ::Rails::Engine
7
+ isolate_namespace Decidim::Elections::Admin
8
+
9
+ paths["db/migrate"] = nil
10
+ paths["lib/tasks"] = nil
11
+
12
+ routes do
13
+ resources :elections do
14
+ resources :questions do
15
+ resources :answers do
16
+ get :proposals_picker, on: :collection
17
+ end
18
+ end
19
+ end
20
+
21
+ root to: "elections#index"
22
+ end
23
+
24
+ def load_seed
25
+ nil
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "decidim/components/namer"
4
+
5
+ Decidim.register_component(:elections) do |component|
6
+ component.engine = Decidim::Elections::Engine
7
+ component.admin_engine = Decidim::Elections::AdminEngine
8
+ component.icon = "decidim/elections/icon.svg"
9
+ component.permissions_class_name = "Decidim::Elections::Permissions"
10
+
11
+ # component.on(:before_destroy) do |instance|
12
+ # # Code executed before removing the component
13
+ # end
14
+
15
+ # These actions permissions can be configured in the admin panel
16
+ # component.actions = %w()
17
+
18
+ component.settings(:global) do |settings|
19
+ settings.attribute :announcement, type: :text, translated: true, editor: true
20
+ end
21
+
22
+ component.settings(:step) do |settings|
23
+ settings.attribute :announcement, type: :text, translated: true, editor: true
24
+ end
25
+
26
+ component.register_resource(:election) do |resource|
27
+ resource.model_class_name = "Decidim::Elections::Election"
28
+ end
29
+
30
+ component.register_resource(:question) do |resource|
31
+ resource.model_class_name = "Decidim::Elections::Question"
32
+ end
33
+
34
+ component.register_resource(:answer) do |resource|
35
+ resource.model_class_name = "Decidim::Elections::Answer"
36
+ end
37
+
38
+ component.register_stat :elections_count, primary: true, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |components, _start_at, _end_at|
39
+ Decidim::Elections::Election.where(component: components).count
40
+ end
41
+
42
+ component.seeds do |participatory_space|
43
+ admin_user = Decidim::User.find_by(
44
+ organization: participatory_space.organization,
45
+ email: "admin@example.org"
46
+ )
47
+
48
+ params = {
49
+ name: Decidim::Components::Namer.new(participatory_space.organization.available_locales, :elections).i18n_name,
50
+ manifest_name: :elections,
51
+ published_at: Time.current,
52
+ participatory_space: participatory_space
53
+ }
54
+
55
+ component = Decidim.traceability.perform_action!(
56
+ "publish",
57
+ Decidim::Component,
58
+ admin_user,
59
+ visibility: "all"
60
+ ) do
61
+ Decidim::Component.create!(params)
62
+ end
63
+
64
+ 3.times do
65
+ election = Decidim.traceability.create!(
66
+ Decidim::Elections::Election,
67
+ admin_user,
68
+ {
69
+ component: component,
70
+ title: Decidim::Faker::Localized.sentence(2),
71
+ subtitle: Decidim::Faker::Localized.sentence(2),
72
+ description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
73
+ Decidim::Faker::Localized.paragraph(3)
74
+ end,
75
+ start_time: 3.weeks.from_now,
76
+ end_time: 3.weeks.from_now + 4.hours
77
+ },
78
+ visibility: "all"
79
+ )
80
+
81
+ 2.times do
82
+ question = Decidim.traceability.create!(
83
+ Decidim::Elections::Question,
84
+ admin_user,
85
+ {
86
+ election: election,
87
+ title: Decidim::Faker::Localized.sentence(2),
88
+ description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
89
+ Decidim::Faker::Localized.paragraph(3)
90
+ end,
91
+ max_selections: Faker::Number.between(0, 5),
92
+ weight: Faker::Number.number(1),
93
+ random_answers_order: Faker::Boolean.boolean(0.5)
94
+ },
95
+ visibility: "all"
96
+ )
97
+
98
+ Faker::Number.between(2, 5).times do
99
+ answer = Decidim.traceability.create!(
100
+ Decidim::Elections::Answer,
101
+ admin_user,
102
+ {
103
+ question: question,
104
+ title: Decidim::Faker::Localized.sentence(2),
105
+ description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
106
+ Decidim::Faker::Localized.paragraph(3)
107
+ end,
108
+ weight: Faker::Number.number(1)
109
+ },
110
+ visibility: "all"
111
+ )
112
+
113
+ Decidim::Attachment.create!(
114
+ title: Decidim::Faker::Localized.sentence(2),
115
+ description: Decidim::Faker::Localized.sentence(5),
116
+ file: File.new(File.join(__dir__, "seeds", "city.jpeg")),
117
+ attached_to: answer
118
+ )
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "decidim/core"
5
+
6
+ module Decidim
7
+ module Elections
8
+ # This is the engine that runs on the public interface of elections.
9
+ class Engine < ::Rails::Engine
10
+ isolate_namespace Decidim::Elections
11
+
12
+ routes do
13
+ resources :elections, only: [:index, :show]
14
+
15
+ root to: "elections#index"
16
+ end
17
+
18
+ initializer "decidim_elections.assets" do |app|
19
+ app.config.assets.precompile += %w(decidim_elections_manifest.js decidim_elections_manifest.css)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/core/test/factories"
4
+
5
+ FactoryBot.define do
6
+ factory :elections_component, parent: :component do
7
+ name { Decidim::Components::Namer.new(participatory_space.organization.available_locales, :elections).i18n_name }
8
+ manifest_name { :elections }
9
+ participatory_space { create(:participatory_process, :with_steps) }
10
+ end
11
+
12
+ factory :election, class: "Decidim::Elections::Election" do
13
+ title { generate_localized_title }
14
+ subtitle { Decidim::Faker::Localized.sentence(3) }
15
+ description { Decidim::Faker::Localized.wrapped("<p>", "</p>") { generate_localized_title } }
16
+ start_time { 1.day.from_now }
17
+ end_time { 3.days.from_now }
18
+ component { create(:elections_component) }
19
+
20
+ trait :started do
21
+ start_time { 1.day.ago }
22
+ end
23
+
24
+ trait :complete do
25
+ after(:build) do |election, _evaluator|
26
+ build_list(:question, 2, :complete, election: election)
27
+ end
28
+ end
29
+ end
30
+
31
+ factory :question, class: "Decidim::Elections::Question" do
32
+ election
33
+ title { generate_localized_title }
34
+ description { Decidim::Faker::Localized.wrapped("<p>", "</p>") { generate_localized_title } }
35
+ max_selections { 1 }
36
+ weight { Faker::Number.number(1) }
37
+ random_answers_order { true }
38
+
39
+ trait :complete do
40
+ after(:build) do |question, _evaluator|
41
+ build_list(:election_answer, 2, question: question)
42
+ end
43
+ end
44
+ end
45
+
46
+ factory :election_answer, class: "Decidim::Elections::Answer" do
47
+ question
48
+ title { generate_localized_title }
49
+ description { Decidim::Faker::Localized.wrapped("<p>", "</p>") { generate_localized_title } }
50
+ weight { Faker::Number.number(1) }
51
+ end
52
+ end