decidim-forms 0.29.3 → 0.30.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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/forms/step_navigation_cell.rb +18 -5
  3. data/app/commands/decidim/forms/admin/update_questionnaire.rb +1 -82
  4. data/app/commands/decidim/forms/admin/update_questions.rb +109 -0
  5. data/app/commands/decidim/forms/answer_questionnaire.rb +10 -3
  6. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +39 -3
  7. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +2 -2
  8. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +12 -4
  9. data/app/forms/decidim/forms/admin/display_condition_form.rb +1 -1
  10. data/app/forms/decidim/forms/admin/questionnaire_form.rb +0 -9
  11. data/app/forms/decidim/forms/admin/questions_form.rb +18 -0
  12. data/app/forms/decidim/forms/answer_choice_form.rb +5 -0
  13. data/app/forms/decidim/forms/answer_form.rb +1 -0
  14. data/app/forms/decidim/forms/questionnaire_form.rb +7 -0
  15. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +1 -1
  16. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +5 -5
  17. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +5 -1
  18. data/app/models/decidim/forms/answer_choice.rb +0 -2
  19. data/app/models/decidim/forms/answer_option.rb +1 -1
  20. data/app/models/decidim/forms/question.rb +10 -0
  21. data/app/packs/entrypoints/decidim_forms.js +0 -1
  22. data/app/packs/entrypoints/decidim_forms_admin.js +6 -0
  23. data/app/packs/src/decidim/forms/admin/publish_answers_buttons.js +72 -0
  24. data/app/packs/src/decidim/forms/forms.js +22 -18
  25. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +1 -1
  26. data/app/presenters/decidim/forms/admin_log/question_presenter.rb +31 -0
  27. data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
  28. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  29. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +1 -1
  30. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +0 -89
  31. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +1 -1
  32. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +3 -3
  33. data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +80 -0
  34. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +0 -20
  35. data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +47 -0
  36. data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +8 -1
  37. data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -1
  38. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +12 -6
  39. data/app/views/decidim/forms/questionnaires/edit.html.erb +47 -0
  40. data/app/views/decidim/forms/questionnaires/show.html.erb +13 -2
  41. data/config/assets.rb +1 -2
  42. data/config/locales/ar.yml +16 -1
  43. data/config/locales/bg.yml +36 -2
  44. data/config/locales/ca.yml +53 -13
  45. data/config/locales/cs.yml +59 -8
  46. data/config/locales/de.yml +52 -12
  47. data/config/locales/el.yml +35 -2
  48. data/config/locales/en.yml +45 -5
  49. data/config/locales/es-MX.yml +55 -15
  50. data/config/locales/es-PY.yml +55 -15
  51. data/config/locales/es.yml +54 -14
  52. data/config/locales/eu.yml +51 -11
  53. data/config/locales/fi-plain.yml +50 -10
  54. data/config/locales/fi.yml +50 -10
  55. data/config/locales/fr-CA.yml +45 -13
  56. data/config/locales/fr.yml +45 -13
  57. data/config/locales/ga-IE.yml +5 -0
  58. data/config/locales/gl.yml +7 -1
  59. data/config/locales/hu.yml +10 -1
  60. data/config/locales/id-ID.yml +7 -1
  61. data/config/locales/it.yml +27 -3
  62. data/config/locales/ja.yml +7 -12
  63. data/config/locales/lb.yml +28 -1
  64. data/config/locales/lt.yml +35 -2
  65. data/config/locales/lv.yml +11 -1
  66. data/config/locales/nl.yml +23 -0
  67. data/config/locales/no.yml +27 -0
  68. data/config/locales/pl.yml +37 -2
  69. data/config/locales/pt-BR.yml +29 -0
  70. data/config/locales/pt.yml +27 -0
  71. data/config/locales/ro-RO.yml +44 -17
  72. data/config/locales/ru.yml +1 -2
  73. data/config/locales/sk.yml +10 -1
  74. data/config/locales/sl.yml +7 -0
  75. data/config/locales/sv.yml +37 -0
  76. data/config/locales/tr-TR.yml +23 -0
  77. data/config/locales/zh-CN.yml +23 -0
  78. data/config/locales/zh-TW.yml +35 -2
  79. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
  80. data/db/migrate/20241122142230_add_survey_answers_published_at_to_questions.rb +7 -0
  81. data/decidim-forms.gemspec +1 -2
  82. data/lib/decidim/api/answer_option_type.rb +1 -1
  83. data/lib/decidim/api/question_type.rb +4 -4
  84. data/lib/decidim/api/questionnaire_type.rb +4 -4
  85. data/lib/decidim/exporters/form_pdf.rb +114 -11
  86. data/lib/decidim/forms/download_your_data_user_answers_serializer.rb +0 -4
  87. data/lib/decidim/forms/test/factories.rb +2 -2
  88. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +44 -4
  89. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +17 -17
  90. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -21
  91. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +70 -94
  92. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +15 -18
  93. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +90 -125
  94. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -25
  95. data/lib/decidim/forms/version.rb +1 -1
  96. data/lib/decidim/forms.rb +0 -1
  97. metadata +18 -33
  98. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +0 -1
  99. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +0 -1
  100. data/app/packs/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -69
  101. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +0 -31
  102. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +0 -13
  103. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +0 -12
  104. data/config/initializers/wicked_pdf.rb +0 -26
  105. data/config/locales/ca-IT.yml +0 -198
  106. data/lib/decidim/exporters/form_pdf_controller_helper.rb +0 -13
@@ -9,6 +9,12 @@ sk:
9
9
  question_type: Typ
10
10
  questionnaire_question:
11
11
  mandatory: Povinné
12
+ errors:
13
+ models:
14
+ answer:
15
+ attributes:
16
+ choices:
17
+ missing: nie je kompletné
12
18
  decidim:
13
19
  forms:
14
20
  admin:
@@ -19,6 +25,7 @@ sk:
19
25
  questionnaires:
20
26
  answer_option:
21
27
  answer_option: Možnosť odpovede
28
+ free_text: Voľný text
22
29
  remove: Odstrániť
23
30
  statement: Prehlásenie
24
31
  edit:
@@ -70,4 +77,6 @@ sk:
70
77
  user_answers_serializer:
71
78
  created_at: Odpovedané na
72
79
  id: ID odpovede
73
- question: Otázka
80
+ registered: Registrovaný
81
+ unregistered: Neregistrovaný
82
+ user_status: Status Užívateľa
@@ -4,3 +4,10 @@ sl:
4
4
  attributes:
5
5
  answer:
6
6
  body: Odgovor
7
+ decidim:
8
+ forms:
9
+ admin:
10
+ questionnaires:
11
+ answers:
12
+ actions:
13
+ export: Izvozi
@@ -4,6 +4,8 @@ sv:
4
4
  attributes:
5
5
  answer:
6
6
  body: Svar
7
+ choices: Alternativ
8
+ selected_choices: Valda alternativ
7
9
  question:
8
10
  max_choices: Högst antal alternativ
9
11
  question_type: Typ
@@ -12,6 +14,15 @@ sv:
12
14
  max_characters: Teckengräns (skriv 0 för obegränsad)
13
15
  errors:
14
16
  models:
17
+ answer:
18
+ attributes:
19
+ add_documents:
20
+ needs_to_be_reattached: Måste bifogas igen
21
+ body:
22
+ too_long: är för långt
23
+ choices:
24
+ missing: är inte fullständiga
25
+ too_many: Du kan välja maximalt %{count}.
15
26
  questionnaire:
16
27
  request_invalid: Det gick inte att hantera begäran. Försök igen.
17
28
  decidim:
@@ -27,14 +38,24 @@ sv:
27
38
  show: Visa svar
28
39
  answer_option:
29
40
  answer_option: Svarsalternativ
41
+ free_text: Fritext
30
42
  remove: Ta bort
31
43
  statement: Påstående
32
44
  answers:
33
45
  actions:
46
+ back: Tillbaka till svar
47
+ export: Exportera
48
+ next: Nästa ›
49
+ previous: "‹ Föregående"
34
50
  show: Visa svar
35
51
  empty: Inga svar ännu
52
+ export:
53
+ answer:
54
+ title: 'Svar #%{number}'
36
55
  export_response:
37
56
  title: survey_user_answers_%{token}
57
+ index:
58
+ title: "%{total} svar totalt"
38
59
  show:
39
60
  title: 'Svar #%{number}'
40
61
  display_condition:
@@ -102,6 +123,9 @@ sv:
102
123
  admin_log:
103
124
  questionnaire:
104
125
  update: "%{user_name} uppdaterade enkäten %{resource_name}"
126
+ errors:
127
+ answer:
128
+ body: Innehåll kan inte vara tomt
105
129
  images:
106
130
  dimensions: "%{width} x %{height} px"
107
131
  processors:
@@ -117,14 +141,21 @@ sv:
117
141
  single_option: Ett alternativ
118
142
  sorting: Sortering
119
143
  title_and_description: Titel och beskrivning
144
+ questionnaire_answer_presenter:
145
+ download_attachment: Ladda ner bilaga
120
146
  questionnaires:
121
147
  answer:
122
148
  invalid: Det gick inte att besvara formuläret.
149
+ max_choices_alert: För många alternativ har valts
123
150
  success: Formuläret har besvarats.
124
151
  question:
125
152
  max_choices: 'Högst antal val: %{n}'
126
153
  show:
127
154
  answer_questionnaire:
155
+ already_have_an_account?: Har du redan ett konto?
156
+ are_you_new?: Ny användare?
157
+ sign_in_description: Logga in för att göra enkäten
158
+ sign_up_description: Skapa ett konto för att göra enkäten
128
159
  title: Besvara formuläret
129
160
  current_step: Steg %{step}
130
161
  empty: Formuläret har inga frågor än.
@@ -151,6 +182,12 @@ sv:
151
182
  submit: Skicka in
152
183
  user_answers_serializer:
153
184
  body: Svar
185
+ completion: Slutfört
154
186
  created_at: Besvarad
155
187
  id: Svars-ID
188
+ ip_hash: IP Hash
156
189
  question: Fråga
190
+ registered: Registrerad
191
+ session_token: Identifierare för användare
192
+ unregistered: Ej registrerad
193
+ user_status: Användarstatus
@@ -4,11 +4,19 @@ tr:
4
4
  attributes:
5
5
  answer:
6
6
  body: Cevap
7
+ choices: Seçenekler
8
+ selected_choices: Seçilmiş seçenekler
7
9
  question:
8
10
  max_choices: Maksimum seçenek sayısı
9
11
  question_type: tip
10
12
  questionnaire_question:
11
13
  mandatory: Zorunlu
14
+ errors:
15
+ models:
16
+ answer:
17
+ attributes:
18
+ choices:
19
+ missing: tamamlanmadı
12
20
  decidim:
13
21
  forms:
14
22
  admin:
@@ -22,14 +30,22 @@ tr:
22
30
  show: Yanıtları göster
23
31
  answer_option:
24
32
  answer_option: Cevap seçeneği
33
+ free_text: Ücretsiz Metin
25
34
  remove: Kaldır
26
35
  statement: Beyan
27
36
  answers:
28
37
  actions:
38
+ back: Yanıtlara dön
39
+ export: Dışa aktar
29
40
  show: Cevapları göster
30
41
  empty: Henüz cevap bulunmuyor
42
+ export:
43
+ answer:
44
+ title: '#%{number} yanıt'
31
45
  export_response:
32
46
  title: survey_user_answers _%{token}
47
+ index:
48
+ title: "%{total} toplam yanıt"
33
49
  show:
34
50
  title: '%{number} cevap'
35
51
  display_condition:
@@ -98,6 +114,7 @@ tr:
98
114
  questionnaires:
99
115
  answer:
100
116
  invalid: Formu yanıtlarken bir sorun oluştu.
117
+ max_choices_alert: Çok fazla seçenek seçilmiş
101
118
  success: Form başarıyla cevaplandı.
102
119
  question:
103
120
  max_choices: 'Maksimum seçenek: %{n}'
@@ -129,6 +146,12 @@ tr:
129
146
  submit: Gönder
130
147
  user_answers_serializer:
131
148
  body: Cevap
149
+ completion: Tamamlanma
132
150
  created_at: Yanıtlandı
133
151
  id: Cevap kimliği
152
+ ip_hash: IP Hash
134
153
  question: Soru
154
+ registered: Kayıtlı
155
+ session_token: Kullanıcı tanımlayıcı
156
+ unregistered: Kayıtlı değil
157
+ user_status: Kullanıcı durumu
@@ -4,11 +4,19 @@ zh-CN:
4
4
  attributes:
5
5
  answer:
6
6
  body: 答案
7
+ choices: 选择
8
+ selected_choices: 选定的选择
7
9
  question:
8
10
  max_choices: 选择的最大数量
9
11
  question_type: 类型
10
12
  questionnaire_question:
11
13
  mandatory: Mandatory
14
+ errors:
15
+ models:
16
+ answer:
17
+ attributes:
18
+ choices:
19
+ missing: 不完成
12
20
  decidim:
13
21
  forms:
14
22
  admin:
@@ -22,14 +30,22 @@ zh-CN:
22
30
  show: 显示回复
23
31
  answer_option:
24
32
  answer_option: 答案选项
33
+ free_text: 免费文本
25
34
  remove: 删除
26
35
  statement: 声明
27
36
  answers:
28
37
  actions:
38
+ back: 回到回应
39
+ export: 导出
29
40
  show: 显示答案
30
41
  empty: 尚无答案
42
+ export:
43
+ answer:
44
+ title: '回复 #%{number}'
31
45
  export_response:
32
46
  title: survey_user_answers_%{token}
47
+ index:
48
+ title: "%{total} 个回复总数"
33
49
  show:
34
50
  title: '答案 #%{number}'
35
51
  display_condition:
@@ -97,6 +113,7 @@ zh-CN:
97
113
  questionnaires:
98
114
  answer:
99
115
  invalid: 回答表单时出现问题。
116
+ max_choices_alert: 选择了太多选项
100
117
  success: 表单回答成功。
101
118
  question:
102
119
  max_choices: '最大选择数: %{n}'
@@ -127,6 +144,12 @@ zh-CN:
127
144
  submit: 提交
128
145
  user_answers_serializer:
129
146
  body: 答案
147
+ completion: 完成
130
148
  created_at: 回答于
131
149
  id: 答案 ID
150
+ ip_hash: IP哈希
132
151
  question: 问
152
+ registered: 已注册
153
+ session_token: 用户标识符
154
+ unregistered: 未注册
155
+ user_status: 用户状态
@@ -4,6 +4,8 @@ zh-TW:
4
4
  attributes:
5
5
  answer:
6
6
  body: 回答
7
+ choices: 選項
8
+ selected_choices: 已選擇的選項
7
9
  question:
8
10
  max_choices: 選擇的最大數量
9
11
  question_type: 類別
@@ -12,8 +14,14 @@ zh-TW:
12
14
  max_characters: 字元限制(如果不需要限制,請設為0)
13
15
  errors:
14
16
  models:
15
- questionnaire:
16
- request_invalid: 處理請求時發生錯誤。請再試一次。
17
+ answer:
18
+ attributes:
19
+ add_documents:
20
+ needs_to_be_reattached: 需要重新附加
21
+ body:
22
+ too_long: 太長
23
+ choices:
24
+ missing: 尚未完成
17
25
  decidim:
18
26
  forms:
19
27
  admin:
@@ -27,14 +35,24 @@ zh-TW:
27
35
  show: 顯示回應
28
36
  answer_option:
29
37
  answer_option: 答案選項:
38
+ free_text: 免費文字
30
39
  remove: 移除
31
40
  statement: 聲明
32
41
  answers:
33
42
  actions:
43
+ back: 返回回覆
44
+ export: 匯出
45
+ next: 下一個 ›
46
+ previous: "‹ 上一篇"
34
47
  show: 顯示答案
35
48
  empty: 目前尚未回答
49
+ export:
50
+ answer:
51
+ title: '回應 #%{number}'
36
52
  export_response:
37
53
  title: 調查問卷使用者回答_%{token}
54
+ index:
55
+ title: "%{total} 個回應總數"
38
56
  show:
39
57
  title: '回答#%{number}'
40
58
  display_condition:
@@ -102,6 +120,9 @@ zh-TW:
102
120
  admin_log:
103
121
  questionnaire:
104
122
  update: "%{user_name} 更新了 %{resource_name} 問卷模板"
123
+ errors:
124
+ answer:
125
+ body: 內容不能為空
105
126
  images:
106
127
  dimensions: "%{width} x %{height} 像素"
107
128
  processors:
@@ -117,14 +138,20 @@ zh-TW:
117
138
  single_option: 單選
118
139
  sorting: 排序中
119
140
  title_and_description: 標題和描述
141
+ questionnaire_answer_presenter:
142
+ download_attachment: 下載附件
120
143
  questionnaires:
121
144
  answer:
122
145
  invalid: 回答表單時出現問題
146
+ max_choices_alert: 選擇的項目太多了
123
147
  success: 表單已成功回答
124
148
  question:
125
149
  max_choices: '最多選擇數量: %{n}'
126
150
  show:
127
151
  answer_questionnaire:
152
+ already_have_an_account?: 已經有帳號了嗎?
153
+ are_you_new?: 新用戶?
154
+ sign_up_description: 建立參與者帳號以填寫問卷
128
155
  title: 回答表單
129
156
  current_step: 步驟%{step}
130
157
  of_total_steps: 的%{total_steps}
@@ -150,6 +177,12 @@ zh-TW:
150
177
  submit: 提交
151
178
  user_answers_serializer:
152
179
  body: 回答
180
+ completion: 完成
153
181
  created_at: 回答時間
154
182
  id: 回答 ID
183
+ ip_hash: IP Hash
155
184
  question: 問題
185
+ registered: 已註冊
186
+ session_token: 使用者識別碼
187
+ unregistered: 未註冊
188
+ user_status: 用戶狀態
@@ -10,7 +10,7 @@ class AddSessionTokenToDecidimFormsAnswers < ActiveRecord::Migration[5.2]
10
10
  add_index :decidim_forms_answers, :session_token
11
11
 
12
12
  Answer.find_each do |answer|
13
- answer.session_token = Digest::MD5.hexdigest("#{answer.decidim_user_id}-#{Rails.application.secrets.secret_key_base}")
13
+ answer.session_token = Digest::MD5.hexdigest("#{answer.decidim_user_id}-#{Rails.application.secret_key_base}")
14
14
  answer.save!
15
15
  end
16
16
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddSurveyAnswersPublishedAtToQuestions < ActiveRecord::Migration[7.0]
4
+ def change
5
+ add_column :decidim_forms_questions, :survey_answers_published_at, :datetime, index: true
6
+ end
7
+ end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  "homepage_uri" => "https://decidim.org",
20
20
  "source_code_uri" => "https://github.com/decidim/decidim"
21
21
  }
22
- s.required_ruby_version = "~> 3.2.0"
22
+ s.required_ruby_version = "~> 3.3.0"
23
23
 
24
24
  s.name = "decidim-forms"
25
25
  s.summary = "Decidim forms"
@@ -33,7 +33,6 @@ Gem::Specification.new do |s|
33
33
  end
34
34
 
35
35
  s.add_dependency "decidim-core", Decidim::Forms.version
36
- s.add_dependency "wicked_pdf", "~> 2.1"
37
36
 
38
37
  s.add_development_dependency "decidim-admin", Decidim::Forms.version
39
38
  s.add_development_dependency "decidim-dev", Decidim::Forms.version
@@ -5,9 +5,9 @@ module Decidim
5
5
  class AnswerOptionType < Decidim::Api::Types::BaseObject
6
6
  description "An answer option for a multi-choice question in a questionnaire"
7
7
 
8
- field :id, GraphQL::Types::ID, "ID of this answer option", null: false
9
8
  field :body, Decidim::Core::TranslatedFieldType, "The text answer response option.", null: false
10
9
  field :free_text, GraphQL::Types::Boolean, "Whether if this answer accepts any free text from the user.", null: false
10
+ field :id, GraphQL::Types::ID, "ID of this answer option", null: false
11
11
  end
12
12
  end
13
13
  end
@@ -7,15 +7,15 @@ module Decidim
7
7
 
8
8
  implements Decidim::Core::TimestampsInterface
9
9
 
10
- field :id, GraphQL::Types::ID, "ID of this question", null: false
10
+ field :answer_options, [AnswerOptionType, { null: true }], "List of answer options in multi-choice questions.", null: false
11
11
  field :body, Decidim::Core::TranslatedFieldType, "What is being asked in this question.", null: false
12
12
  field :description, Decidim::Core::TranslatedFieldType, "The description of this question.", null: true
13
+ field :id, GraphQL::Types::ID, "ID of this question", null: false
13
14
  field :mandatory, GraphQL::Types::Boolean, "Whether if this question is mandatory.", null: false
14
- field :position, GraphQL::Types::Int, "Order position of the question in the questionnaire", null: true
15
- field :max_choices, GraphQL::Types::Int, "On questions with answer options, maximum number of choices the user has", null: true
16
15
  field :max_characters, GraphQL::Types::Int, "On questions with free text answers, maximum number of characters the answer can have (0 if no limit)", null: false
16
+ field :max_choices, GraphQL::Types::Int, "On questions with answer options, maximum number of choices the user has", null: true
17
+ field :position, GraphQL::Types::Int, "Order position of the question in the questionnaire", null: true
17
18
  field :question_type, GraphQL::Types::String, "Type of question.", null: true
18
- field :answer_options, [AnswerOptionType, { null: true }], "List of answer options in multi-choice questions.", null: false
19
19
  end
20
20
  end
21
21
  end
@@ -7,13 +7,13 @@ module Decidim
7
7
 
8
8
  implements Decidim::Core::TimestampsInterface
9
9
 
10
- field :id, GraphQL::Types::ID, "ID of this questionnaire", null: false
11
- field :title, Decidim::Core::TranslatedFieldType, "The title of this questionnaire.", null: false
12
10
  field :description, Decidim::Core::TranslatedFieldType, "The description of this questionnaire.", null: true
13
- field :tos, Decidim::Core::TranslatedFieldType, "The Terms of Service for this questionnaire.", null: true
14
- field :for_type, GraphQL::Types::String, "Type of entity using this questionnaire.", method: :questionnaire_for_type, null: true
15
11
  field :for_entity, QuestionnaireEntityInterface, "Entity using this questionnaire.", method: :questionnaire_for, null: true
12
+ field :for_type, GraphQL::Types::String, "Type of entity using this questionnaire.", method: :questionnaire_for_type, null: true
13
+ field :id, GraphQL::Types::ID, "ID of this questionnaire", null: false
16
14
  field :questions, [Decidim::Forms::QuestionType, { null: true }], "Questions in this questionnaire.", null: false
15
+ field :title, Decidim::Core::TranslatedFieldType, "The title of this questionnaire.", null: false
16
+ field :tos, Decidim::Core::TranslatedFieldType, "The Terms of Service for this questionnaire.", null: true
17
17
  end
18
18
  end
19
19
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "wicked_pdf"
4
-
5
3
  module Decidim
6
4
  module Exporters
7
5
  # Inherits from abstract PDF exporter. This class is used to set
@@ -9,25 +7,130 @@ module Decidim
9
7
  #
10
8
  class FormPDF < PDF
11
9
  # i18n-tasks-use t('decidim.admin.exports.formats.FormPDF')
10
+ include ActionView::Helpers::NumberHelper
11
+ include Decidim::Forms::Admin::QuestionnaireAnswersHelper
12
+
13
+ class QuestionnaireAnswerPresenter < Decidim::Forms::Admin::QuestionnaireAnswerPresenter
14
+ def choice(choice_hash)
15
+ render_body_for choice_hash
16
+ end
17
+
18
+ delegate :attachments, to: :answer
19
+
20
+ def body
21
+ return { string: answer.body } if answer.body.present?
22
+ return { attachments: answer.attachments } if answer.attachments.any?
23
+ return { string: "-" } if answer.choices.empty?
24
+
25
+ choices = answer.choices.map do |choice|
26
+ {
27
+ answer_option_body: choice.try(:answer_option).try(:translated_body),
28
+ choice_body: body_or_custom_body(choice)
29
+ }
30
+ end
31
+
32
+ return { single_option: choice(choices.first) } if answer.question.question_type == "single_option"
12
33
 
13
- def controller
14
- @controller ||= FormPDFControllerHelper.new
34
+ { multiple_option: choices.map { |c| choice(c) } }
35
+ end
15
36
  end
16
37
 
17
- def template
18
- "decidim/forms/admin/questionnaires/answers/export/pdf"
38
+ class ParticipantPresenter < Decidim::Forms::Admin::QuestionnaireParticipantPresenter
39
+ def answers
40
+ siblings.map { |answer| QuestionnaireAnswerPresenter.new(answer:) }
41
+ end
19
42
  end
20
43
 
21
- def layout
22
- "decidim/forms/admin/questionnaires/questionnaire_answers"
44
+ protected
45
+
46
+ def add_data!
47
+ composer.text(decidim_sanitize(translated_attribute(questionnaire.title), strip_tags: true), style: :h1)
48
+ composer.text(decidim_sanitize(translated_attribute(questionnaire.description), strip_tags: true), style: :description)
49
+ composer.text(I18n.t("title", scope: "decidim.forms.admin.questionnaires.answers.index", total: collection.count), style: :section_title)
50
+
51
+ local_collection = collection.map { |answer| ParticipantPresenter.new(participant: answer.first) }
52
+
53
+ local_collection.each_with_index do |record, index|
54
+ add_response_box(record, index)
55
+ end
23
56
  end
24
57
 
25
- def locals
58
+ def questionnaire = collection.first.first.questionnaire
59
+
60
+ def styles
26
61
  {
27
- questionnaire: collection.first.first.questionnaire,
28
- collection: collection.map { |answer| Decidim::Forms::Admin::QuestionnaireParticipantPresenter.new(participant: answer.first) }
62
+ h1: { font: bold_font, font_size: 18, margin: [0, 0, 10, 0] },
63
+ th: { font: bold_font, font_size: 10, margin: [0, 0, 10, 0] },
64
+ td: { font:, font_size: 10, margin: [0, 0, 10, 0] },
65
+ description: { font:, margin: [0, 0, 10, 0], font_size: 10 },
66
+ section_title: { font: bold_font, margin: [15, 0, 15, 0], font_size: 16 },
67
+ question_title: { font: bold_font, margin: [10, 0, 10, 0], font_size: 12 },
68
+ question_answer: { font:, margin: [10, 0, 10, 0], font_size: 10 },
69
+ file_info: { font:, margin: [10, 0, 10, 0], font_size: 8 },
70
+ link: { font:, margin: [10, 0, 10, 0], font_size: 10, underline: true }
29
71
  }
30
72
  end
73
+
74
+ def header
75
+ [
76
+ layout.text(I18n.t("session_token", scope: "decidim.forms.user_answers_serializer"), style: :th),
77
+ layout.text(I18n.t("user_status", scope: "decidim.forms.user_answers_serializer"), style: :th),
78
+ layout.text(I18n.t("ip_hash", scope: "decidim.forms.user_answers_serializer"), style: :th),
79
+ layout.text(I18n.t("completion", scope: "decidim.forms.user_answers_serializer"), style: :th),
80
+ layout.text(I18n.t("created_at", scope: "decidim.forms.user_answers_serializer"), style: :th)
81
+ ]
82
+ end
83
+
84
+ def add_user_data(record)
85
+ cells = [
86
+ layout.text(record.session_token, style: :td),
87
+ layout.text(record.status, style: :td),
88
+ layout.text(record.ip_hash, style: :td),
89
+ layout.text(display_percentage(record.completion), style: :td),
90
+ layout.text(I18n.l(record.answered_at, format: :short), style: :td)
91
+ ]
92
+ composer.table([cells], header: ->(_table) { [header] }, cell_style: { border: { width: 0 } })
93
+ end
94
+
95
+ def add_response_box(record, index)
96
+ composer.text(I18n.t("title", number: index + 1, scope: "decidim.forms.admin.questionnaires.answers.export.answer"), style: :section_title)
97
+ add_user_data(record)
98
+
99
+ record.answers.each do |answer|
100
+ composer.text(answer.question, style: :question_title)
101
+ add_answer_body(answer)
102
+ end
103
+ end
104
+
105
+ def add_answer_body(answer)
106
+ return composer.text(answer.body[:string], style: :question_answer) if answer.body.has_key?(:string)
107
+
108
+ if answer.attachments.any?
109
+ composer.list(marker_type: :disc) do |sub_list|
110
+ answer.attachments.each do |attachment|
111
+ sub_list.formatted_text(
112
+ [{ link: attachment.url,
113
+ text: translated_attribute(attachment.title).presence ||
114
+ I18n.t("download_attachment", scope: "decidim.forms.questionnaire_answer_presenter"),
115
+ style: :link },
116
+ " (#{attachment.file_type} #{number_to_human_size(attachment.file_size)})"],
117
+ style: :file_info
118
+ )
119
+ end
120
+ end
121
+ return
122
+ end
123
+
124
+ if answer.body.has_key?(:single_option)
125
+ composer.list(marker_type: :disc) do |sub_list|
126
+ sub_list.text(answer.body[:single_option], style: :question_answer)
127
+ end
128
+ else
129
+ composer.list(marker_type: :disc) do |sub_list|
130
+ answer.body[:multiple_option].map { |choice| sub_list.text(choice, style: :question_answer) }
131
+ end
132
+ end
133
+ end
31
134
  end
32
135
  end
33
136
  end
@@ -8,10 +8,6 @@ module Decidim
8
8
  def serialize
9
9
  {
10
10
  id: resource.id,
11
- user: {
12
- name: resource.user.name,
13
- email: resource.user.email
14
- },
15
11
  questionnaire: {
16
12
  id: resource.question.questionnaire.id,
17
13
  title: translated_attribute(resource.question.questionnaire.title),
@@ -149,8 +149,8 @@ FactoryBot.define do
149
149
 
150
150
  trait :with_attachments do
151
151
  after(:create) do |answer, evaluator|
152
- create :attachment, :with_image, attached_to: answer, skip_injection: evaluator.skip_injection
153
- create :attachment, :with_pdf, attached_to: answer, skip_injection: evaluator.skip_injection
152
+ create(:attachment, :with_image, attached_to: answer, skip_injection: evaluator.skip_injection)
153
+ create(:attachment, :with_pdf, attached_to: answer, skip_injection: evaluator.skip_injection)
154
154
  end
155
155
  end
156
156
  end